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 | WS_CHILD)) == WS_CAPTION )
1147 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1150 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1153 if (HIWORD(cs->hInstance))
1154 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1156 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1158 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1162 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1163 WIN_ReleaseWndPtr( wndPtr );
1165 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1167 WIN_DestroyWindow( hwnd );
1171 /* Notify the parent window only */
1173 send_parent_notify( hwnd, WM_CREATE );
1174 if (!IsWindow( hwnd )) return 0;
1176 if (cs->style & WS_VISIBLE)
1178 /* in case WS_VISIBLE got set in the meantime */
1179 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1180 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1181 WIN_ReleasePtr( wndPtr );
1182 ShowWindow( hwnd, sw );
1185 /* Call WH_SHELL hook */
1187 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1188 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1190 TRACE("created window %p\n", hwnd);
1195 /***********************************************************************
1196 * CreateWindow (USER.41)
1198 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1199 DWORD style, INT16 x, INT16 y, INT16 width,
1200 INT16 height, HWND16 parent, HMENU16 menu,
1201 HINSTANCE16 instance, LPVOID data )
1203 return CreateWindowEx16( 0, className, windowName, style,
1204 x, y, width, height, parent, menu, instance, data );
1208 /***********************************************************************
1209 * CreateWindowEx (USER.452)
1211 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1212 LPCSTR windowName, DWORD style, INT16 x,
1213 INT16 y, INT16 width, INT16 height,
1214 HWND16 parent, HMENU16 menu,
1215 HINSTANCE16 instance, LPVOID data )
1221 /* Find the class atom */
1223 if (HIWORD(className))
1225 if (!(classAtom = GlobalFindAtomA( className )))
1227 ERR( "bad class name %s\n", debugstr_a(className) );
1233 classAtom = LOWORD(className);
1234 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1236 ERR( "bad atom %x\n", classAtom);
1242 /* Fix the coordinates */
1244 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1245 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1246 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1247 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1249 /* Create the window */
1251 cs.lpCreateParams = data;
1252 cs.hInstance = HINSTANCE_32(instance);
1253 cs.hMenu = HMENU_32(menu);
1254 cs.hwndParent = WIN_Handle32( parent );
1256 cs.lpszName = windowName;
1257 cs.lpszClass = className;
1258 cs.dwExStyle = exStyle;
1260 return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1264 /***********************************************************************
1265 * CreateWindowExA (USER32.@)
1267 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1268 LPCSTR windowName, DWORD style, INT x,
1269 INT y, INT width, INT height,
1270 HWND parent, HMENU menu,
1271 HINSTANCE instance, LPVOID data )
1278 instance=GetModuleHandleA(NULL);
1280 if(exStyle & WS_EX_MDICHILD)
1281 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1283 /* Find the class atom */
1285 if (HIWORD(className))
1287 if (!(classAtom = GlobalFindAtomA( className )))
1289 ERR( "bad class name %s\n", debugstr_a(className) );
1295 classAtom = LOWORD(className);
1296 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1298 ERR( "bad atom %x\n", classAtom);
1304 /* Create the window */
1306 cs.lpCreateParams = data;
1307 cs.hInstance = instance;
1309 cs.hwndParent = parent;
1315 cs.lpszName = windowName;
1316 cs.lpszClass = className;
1317 cs.dwExStyle = exStyle;
1319 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1323 /***********************************************************************
1324 * CreateWindowExW (USER32.@)
1326 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1327 LPCWSTR windowName, DWORD style, INT x,
1328 INT y, INT width, INT height,
1329 HWND parent, HMENU menu,
1330 HINSTANCE instance, LPVOID data )
1337 instance=GetModuleHandleW(NULL);
1339 if(exStyle & WS_EX_MDICHILD)
1340 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1342 /* Find the class atom */
1344 if (HIWORD(className))
1346 if (!(classAtom = GlobalFindAtomW( className )))
1348 ERR( "bad class name %s\n", debugstr_w(className) );
1354 classAtom = LOWORD(className);
1355 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1357 ERR( "bad atom %x\n", classAtom);
1363 /* Create the window */
1365 cs.lpCreateParams = data;
1366 cs.hInstance = instance;
1368 cs.hwndParent = parent;
1374 cs.lpszName = windowName;
1375 cs.lpszClass = className;
1376 cs.dwExStyle = exStyle;
1378 /* Note: we rely on the fact that CREATESTRUCTA and */
1379 /* CREATESTRUCTW have the same layout. */
1380 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1384 /***********************************************************************
1385 * WIN_SendDestroyMsg
1387 static void WIN_SendDestroyMsg( HWND hwnd )
1391 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1393 if (hwnd == info.hwndCaret) DestroyCaret();
1395 if (USER_Driver.pResetSelectionOwner)
1396 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1399 * Send the WM_DESTROY to the window.
1401 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1404 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1405 * make sure that the window still exists when we come back.
1412 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1414 /* start from the end (FIXME: is this needed?) */
1415 for (i = 0; pWndArray[i]; i++) ;
1419 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1421 HeapFree( GetProcessHeap(), 0, pWndArray );
1424 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1428 /***********************************************************************
1429 * DestroyWindow (USER32.@)
1431 BOOL WINAPI DestroyWindow( HWND hwnd )
1436 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1438 SetLastError( ERROR_ACCESS_DENIED );
1442 TRACE("(%p)\n", hwnd);
1444 /* Look whether the focus is within the tree of windows we will
1448 if (h == hwnd || IsChild( hwnd, h ))
1450 HWND parent = GetAncestor( hwnd, GA_PARENT );
1451 if (parent == GetDesktopWindow()) parent = 0;
1457 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1459 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1463 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1464 send_parent_notify( hwnd, WM_DESTROY );
1466 else if (!GetWindow( hwnd, GW_OWNER ))
1468 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1469 /* FIXME: clean up palette - see "Internals" p.352 */
1472 if (!IsWindow(hwnd)) return TRUE;
1474 if (USER_Driver.pResetSelectionOwner)
1475 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1477 /* Hide the window */
1479 if (!ShowWindow( hwnd, SW_HIDE ))
1481 if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd );
1483 if (!IsWindow(hwnd)) return TRUE;
1485 /* Recursively destroy owned windows */
1492 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1495 for (i = 0; list[i]; i++)
1497 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1498 if (WIN_IsCurrentThread( list[i] ))
1500 DestroyWindow( list[i] );
1504 WIN_SetOwner( list[i], 0 );
1506 HeapFree( GetProcessHeap(), 0, list );
1508 if (!got_one) break;
1512 /* Send destroy messages */
1514 WIN_SendDestroyMsg( hwnd );
1515 if (!IsWindow( hwnd )) return TRUE;
1517 /* Unlink now so we won't bother with the children later on */
1519 WIN_UnlinkWindow( hwnd );
1521 /* Destroy the window storage */
1523 WIN_DestroyWindow( hwnd );
1528 /***********************************************************************
1529 * CloseWindow (USER32.@)
1531 BOOL WINAPI CloseWindow( HWND hwnd )
1533 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1534 ShowWindow( hwnd, SW_MINIMIZE );
1539 /***********************************************************************
1540 * OpenIcon (USER32.@)
1542 BOOL WINAPI OpenIcon( HWND hwnd )
1544 if (!IsIconic( hwnd )) return FALSE;
1545 ShowWindow( hwnd, SW_SHOWNORMAL );
1550 /***********************************************************************
1553 * Implementation of FindWindow() and FindWindowEx().
1555 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1560 WCHAR *buffer = NULL;
1562 if (!parent) parent = GetDesktopWindow();
1565 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1566 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1569 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1573 child = WIN_GetFullHandle( child );
1574 while (list[i] && list[i] != child) i++;
1575 if (!list[i]) goto done;
1576 i++; /* start from next window */
1583 if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1590 if (list) HeapFree( GetProcessHeap(), 0, list );
1591 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1597 /***********************************************************************
1598 * FindWindowA (USER32.@)
1600 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1602 HWND ret = FindWindowExA( 0, 0, className, title );
1603 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1608 /***********************************************************************
1609 * FindWindowExA (USER32.@)
1611 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1612 LPCSTR className, LPCSTR title )
1621 /* If the atom doesn't exist, then no class */
1622 /* with this name exists either. */
1623 if (!(atom = GlobalFindAtomA( className )))
1625 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1629 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1631 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1632 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1633 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1634 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1635 HeapFree( GetProcessHeap(), 0, buffer );
1640 /***********************************************************************
1641 * FindWindowExW (USER32.@)
1643 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1644 LPCWSTR className, LPCWSTR title )
1650 /* If the atom doesn't exist, then no class */
1651 /* with this name exists either. */
1652 if (!(atom = GlobalFindAtomW( className )))
1654 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1658 return WIN_FindWindow( parent, child, atom, title );
1662 /***********************************************************************
1663 * FindWindowW (USER32.@)
1665 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1667 return FindWindowExW( 0, 0, className, title );
1671 /**********************************************************************
1672 * GetDesktopWindow (USER32.@)
1674 HWND WINAPI GetDesktopWindow(void)
1676 if (pWndDesktop) return pWndDesktop->hwndSelf;
1677 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" );
1683 /*******************************************************************
1684 * EnableWindow (USER32.@)
1686 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1693 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1694 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1698 TRACE("( %p, %d )\n", hwnd, enable);
1700 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1701 style = wndPtr->dwStyle;
1702 retvalue = ((style & WS_DISABLED) != 0);
1703 WIN_ReleasePtr( wndPtr );
1705 if (enable && retvalue)
1707 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1708 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1710 else if (!enable && !retvalue)
1712 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1714 WIN_SetStyle( hwnd, style | WS_DISABLED );
1716 if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
1717 SetFocus( 0 ); /* A disabled window can't have the focus */
1719 if (hwnd == GetCapture() || IsChild(hwnd, GetCapture()))
1720 ReleaseCapture(); /* A disabled window can't capture the mouse */
1722 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1728 /***********************************************************************
1729 * IsWindowEnabled (USER32.@)
1731 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1733 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1737 /***********************************************************************
1738 * IsWindowUnicode (USER32.@)
1740 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1745 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1746 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1747 WIN_ReleaseWndPtr(wndPtr);
1752 /**********************************************************************
1753 * GetWindowWord (USER32.@)
1755 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1760 WND *wndPtr = WIN_GetPtr( hwnd );
1763 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1766 if (wndPtr == WND_OTHER_PROCESS)
1768 if (IsWindow( hwnd ))
1769 FIXME( "(%d) not supported yet on other process window %p\n", offset, hwnd );
1770 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1773 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1775 WARN("Invalid offset %d\n", offset );
1776 SetLastError( ERROR_INVALID_INDEX );
1778 else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1779 WIN_ReleasePtr( wndPtr );
1785 case GWL_HWNDPARENT:
1786 return GetWindowLongW( hwnd, offset );
1790 LONG ret = GetWindowLongW( hwnd, offset );
1792 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1796 WARN("Invalid offset %d\n", offset );
1802 /**********************************************************************
1803 * SetWindowWord (USER32.@)
1805 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1814 case GWL_HWNDPARENT:
1815 return SetWindowLongW( hwnd, offset, (UINT)newval );
1819 WARN("Invalid offset %d\n", offset );
1820 SetLastError( ERROR_INVALID_INDEX );
1825 wndPtr = WIN_GetPtr( hwnd );
1826 if (wndPtr == WND_OTHER_PROCESS)
1829 FIXME( "set %d <- %x not supported yet on other process window %p\n",
1830 offset, newval, hwnd );
1835 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1839 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1841 WARN("Invalid offset %d\n", offset );
1842 WIN_ReleasePtr(wndPtr);
1843 SetLastError( ERROR_INVALID_INDEX );
1846 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1849 WIN_ReleasePtr(wndPtr);
1854 /**********************************************************************
1857 * Helper function for GetWindowLong().
1859 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1864 if (offset == GWL_HWNDPARENT)
1866 HWND parent = GetAncestor( hwnd, GA_PARENT );
1867 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1868 return (LONG)parent;
1871 if (!(wndPtr = WIN_GetPtr( hwnd )))
1873 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1877 if (wndPtr == WND_OTHER_PROCESS)
1882 FIXME( "(%d) not supported on other process window %p\n", offset, hwnd );
1883 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1886 if (offset == GWL_WNDPROC)
1888 SetLastError( ERROR_ACCESS_DENIED );
1891 SERVER_START_REQ( set_window_info )
1894 req->flags = 0; /* don't set anything, just retrieve */
1895 if (!wine_server_call_err( req ))
1899 case GWL_STYLE: retvalue = reply->old_style; break;
1900 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1901 case GWL_ID: retvalue = reply->old_id; break;
1902 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1903 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1905 SetLastError( ERROR_INVALID_INDEX );
1914 /* now we have a valid wndPtr */
1918 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1921 * Some programs try to access last element from 16 bit
1922 * code using illegal offset value. Hopefully this is
1923 * what those programs really expect.
1925 if (type == WIN_PROC_16 &&
1926 wndPtr->cbWndExtra >= 4 &&
1927 offset == wndPtr->cbWndExtra - sizeof(WORD))
1929 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1931 ERR( "- replaced invalid offset %d with %d\n",
1934 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1935 WIN_ReleasePtr( wndPtr );
1938 WARN("Invalid offset %d\n", offset );
1939 WIN_ReleasePtr( wndPtr );
1940 SetLastError( ERROR_INVALID_INDEX );
1943 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1944 /* Special case for dialog window procedure */
1945 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1946 retvalue = (LONG)WINPROC_GetProc( (WNDPROC)retvalue, type );
1947 WIN_ReleasePtr( wndPtr );
1953 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
1954 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1955 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1956 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
1957 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1958 case GWL_HINSTANCE: retvalue = (LONG)wndPtr->hInstance; break;
1960 WARN("Unknown offset %d\n", offset );
1961 SetLastError( ERROR_INVALID_INDEX );
1964 WIN_ReleasePtr(wndPtr);
1969 /**********************************************************************
1972 * Helper function for SetWindowLong().
1974 * 0 is the failure code. However, in the case of failure SetLastError
1975 * must be set to distinguish between a 0 return value and a failure.
1977 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1978 WINDOWPROCTYPE type )
1983 TRACE( "%p %d %lx %x\n", hwnd, offset, newval, type );
1985 if (!WIN_IsCurrentProcess( hwnd ))
1987 if (offset == GWL_WNDPROC)
1989 SetLastError( ERROR_ACCESS_DENIED );
1992 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1995 wndPtr = WIN_GetPtr( hwnd );
1996 if (wndPtr->hwndSelf == GetDesktopWindow())
1998 /* can't change anything on the desktop window */
1999 WIN_ReleasePtr( wndPtr );
2000 SetLastError( ERROR_ACCESS_DENIED );
2006 LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
2007 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2009 WARN("Invalid offset %d\n", offset );
2010 WIN_ReleasePtr( wndPtr );
2011 SetLastError( ERROR_INVALID_INDEX );
2014 /* Special case for dialog window procedure */
2015 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2017 retval = (LONG)WINPROC_GetProc( (WNDPROC)*ptr, type );
2018 WINPROC_SetProc( (WNDPROC *)ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2019 WIN_ReleasePtr( wndPtr );
2024 WIN_ReleasePtr( wndPtr );
2031 /* first some special cases */
2036 style.styleOld = wndPtr->dwStyle;
2037 style.styleNew = newval;
2038 WIN_ReleasePtr( wndPtr );
2039 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2040 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2041 newval = style.styleNew;
2043 case GWL_HWNDPARENT:
2044 if (wndPtr->parent == GetDesktopWindow())
2046 WIN_ReleasePtr( wndPtr );
2047 return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
2051 WIN_ReleasePtr( wndPtr );
2052 return (LONG)SetParent( hwnd, (HWND)newval );
2055 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2056 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2057 WIN_ReleasePtr( wndPtr );
2064 WIN_ReleasePtr( wndPtr );
2065 WARN("Invalid offset %d\n", offset );
2066 SetLastError( ERROR_INVALID_INDEX );
2070 SERVER_START_REQ( set_window_info )
2076 req->flags = SET_WIN_STYLE;
2077 req->style = newval;
2080 req->flags = SET_WIN_EXSTYLE;
2081 req->ex_style = newval;
2084 req->flags = SET_WIN_ID;
2088 req->flags = SET_WIN_INSTANCE;
2089 req->instance = (void *)newval;
2092 req->flags = SET_WIN_USERDATA;
2093 req->user_data = (void *)newval;
2096 if ((ok = !wine_server_call_err( req )))
2101 wndPtr->dwStyle = newval;
2102 retval = reply->old_style;
2105 wndPtr->dwExStyle = newval;
2106 retval = reply->old_ex_style;
2109 wndPtr->wIDmenu = newval;
2110 retval = reply->old_id;
2113 wndPtr->hInstance = (HINSTANCE)newval;
2114 retval = (ULONG_PTR)reply->old_instance;
2117 wndPtr->userdata = newval;
2118 retval = (ULONG_PTR)reply->old_user_data;
2124 WIN_ReleasePtr( wndPtr );
2128 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2129 USER_Driver.pSetWindowStyle( hwnd, retval );
2131 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2132 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2139 /**********************************************************************
2140 * GetWindowLong (USER.135)
2142 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2144 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2148 /**********************************************************************
2149 * GetWindowLongA (USER32.@)
2151 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2153 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2157 /**********************************************************************
2158 * GetWindowLongW (USER32.@)
2160 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2162 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2166 /**********************************************************************
2167 * SetWindowLong (USER.136)
2169 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2171 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2175 /**********************************************************************
2176 * SetWindowLongA (USER32.@)
2178 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2180 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2184 /**********************************************************************
2185 * SetWindowLongW (USER32.@) Set window attribute
2187 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2188 * value in a window's extra memory.
2190 * The _hwnd_ parameter specifies the window. is the handle to a
2191 * window that has extra memory. The _newval_ parameter contains the
2192 * new attribute or extra memory value. If positive, the _offset_
2193 * parameter is the byte-addressed location in the window's extra
2194 * memory to set. If negative, _offset_ specifies the window
2195 * attribute to set, and should be one of the following values:
2197 * GWL_EXSTYLE The window's extended window style
2199 * GWL_STYLE The window's window style.
2201 * GWL_WNDPROC Pointer to the window's window procedure.
2203 * GWL_HINSTANCE The window's pplication instance handle.
2205 * GWL_ID The window's identifier.
2207 * GWL_USERDATA The window's user-specified data.
2209 * If the window is a dialog box, the _offset_ parameter can be one of
2210 * the following values:
2212 * DWL_DLGPROC The address of the window's dialog box procedure.
2214 * DWL_MSGRESULT The return value of a message
2215 * that the dialog box procedure processed.
2217 * DWL_USER Application specific information.
2221 * If successful, returns the previous value located at _offset_. Otherwise,
2226 * Extra memory for a window class is specified by a nonzero cbWndExtra
2227 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2228 * time of class creation.
2230 * Using GWL_WNDPROC to set a new window procedure effectively creates
2231 * a window subclass. Use CallWindowProc() in the new windows procedure
2232 * to pass messages to the superclass's window procedure.
2234 * The user data is reserved for use by the application which created
2237 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2238 * instead, call the EnableWindow() function to change the window's
2241 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2242 * SetParent() instead.
2245 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2246 * it sends WM_STYLECHANGING before changing the settings
2247 * and WM_STYLECHANGED afterwards.
2248 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2250 LONG WINAPI SetWindowLongW(
2251 HWND hwnd, /* [in] window to alter */
2252 INT offset, /* [in] offset, in bytes, of location to alter */
2253 LONG newval /* [in] new value of location */
2255 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2259 /*******************************************************************
2260 * GetWindowTextA (USER32.@)
2262 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2266 if (WIN_IsCurrentProcess( hwnd ))
2267 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2269 /* when window belongs to other process, don't send a message */
2270 if (nMaxCount <= 0) return 0;
2271 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2272 get_server_window_text( hwnd, buffer, nMaxCount );
2273 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2274 lpString[nMaxCount-1] = 0;
2275 HeapFree( GetProcessHeap(), 0, buffer );
2276 return strlen(lpString);
2280 /*******************************************************************
2281 * InternalGetWindowText (USER32.@)
2283 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2287 if (nMaxCount <= 0) return 0;
2288 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2289 if (win != WND_OTHER_PROCESS)
2291 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2292 else lpString[0] = 0;
2293 WIN_ReleasePtr( win );
2297 get_server_window_text( hwnd, lpString, nMaxCount );
2299 return strlenW(lpString);
2303 /*******************************************************************
2304 * GetWindowTextW (USER32.@)
2306 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2308 if (WIN_IsCurrentProcess( hwnd ))
2309 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2311 /* when window belongs to other process, don't send a message */
2312 if (nMaxCount <= 0) return 0;
2313 get_server_window_text( hwnd, lpString, nMaxCount );
2314 return strlenW(lpString);
2318 /*******************************************************************
2319 * SetWindowText (USER32.@)
2320 * SetWindowTextA (USER32.@)
2322 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2324 if (!WIN_IsCurrentProcess( hwnd ))
2326 FIXME( "cannot set text %s of other process window %p\n", debugstr_a(lpString), hwnd );
2327 SetLastError( ERROR_ACCESS_DENIED );
2330 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2334 /*******************************************************************
2335 * SetWindowTextW (USER32.@)
2337 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2339 if (!WIN_IsCurrentProcess( hwnd ))
2341 FIXME( "cannot set text %s of other process window %p\n", debugstr_w(lpString), hwnd );
2342 SetLastError( ERROR_ACCESS_DENIED );
2345 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2349 /*******************************************************************
2350 * GetWindowTextLengthA (USER32.@)
2352 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2354 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2357 /*******************************************************************
2358 * GetWindowTextLengthW (USER32.@)
2360 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2362 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2366 /*******************************************************************
2367 * IsWindow (USER32.@)
2369 BOOL WINAPI IsWindow( HWND hwnd )
2374 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2376 if (ptr != WND_OTHER_PROCESS)
2378 WIN_ReleasePtr( ptr );
2382 /* check other processes */
2383 SERVER_START_REQ( get_window_info )
2386 ret = !wine_server_call_err( req );
2393 /***********************************************************************
2394 * GetWindowThreadProcessId (USER32.@)
2396 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2401 if (!(ptr = WIN_GetPtr( hwnd )))
2403 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2407 if (ptr != WND_OTHER_PROCESS)
2409 /* got a valid window */
2411 if (process) *process = GetCurrentProcessId();
2412 WIN_ReleasePtr( ptr );
2416 /* check other processes */
2417 SERVER_START_REQ( get_window_info )
2420 if (!wine_server_call_err( req ))
2422 tid = (DWORD)reply->tid;
2423 if (process) *process = (DWORD)reply->pid;
2431 /*****************************************************************
2432 * GetParent (USER32.@)
2434 HWND WINAPI GetParent( HWND hwnd )
2439 if (!(wndPtr = WIN_GetPtr( hwnd )))
2441 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2444 if (wndPtr == WND_OTHER_PROCESS)
2446 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2447 if (style & (WS_POPUP | WS_CHILD))
2449 SERVER_START_REQ( get_window_tree )
2452 if (!wine_server_call_err( req ))
2454 if (style & WS_POPUP) retvalue = reply->owner;
2455 else if (style & WS_CHILD) retvalue = reply->parent;
2463 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2464 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2465 WIN_ReleasePtr( wndPtr );
2471 /*****************************************************************
2472 * GetAncestor (USER32.@)
2474 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2477 HWND *list, ret = 0;
2482 if (!(win = WIN_GetPtr( hwnd )))
2484 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2487 if (win != WND_OTHER_PROCESS)
2490 WIN_ReleasePtr( win );
2492 else /* need to query the server */
2494 SERVER_START_REQ( get_window_tree )
2497 if (!wine_server_call_err( req )) ret = reply->parent;
2504 if (!(list = WIN_ListParents( hwnd ))) return 0;
2506 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2510 while (list[count]) count++;
2511 ret = list[count - 2]; /* get the one before the desktop */
2513 HeapFree( GetProcessHeap(), 0, list );
2517 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2520 HWND parent = GetParent( ret );
2530 /*****************************************************************
2531 * SetParent (USER32.@)
2533 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2536 HWND retvalue, full_handle;
2539 if (!parent) parent = GetDesktopWindow();
2540 else parent = WIN_GetFullHandle( parent );
2542 if (!IsWindow( parent ))
2544 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2548 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2549 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2553 if (USER_Driver.pSetParent)
2554 return USER_Driver.pSetParent( hwnd, parent );
2556 /* Windows hides the window first, then shows it again
2557 * including the WM_SHOWWINDOW messages and all */
2558 was_visible = ShowWindow( hwnd, SW_HIDE );
2560 if (!IsWindow( parent )) return 0;
2561 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2563 retvalue = wndPtr->parent; /* old parent */
2564 if (parent != retvalue)
2566 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2568 if (parent != GetDesktopWindow()) /* a child window */
2570 if (!(wndPtr->dwStyle & WS_CHILD))
2572 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2573 if (menu) DestroyMenu( menu );
2577 WIN_ReleasePtr( wndPtr );
2579 /* SetParent additionally needs to make hwnd the topmost window
2580 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2581 WM_WINDOWPOSCHANGED notification messages.
2583 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2584 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2585 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2586 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2591 /*******************************************************************
2592 * IsChild (USER32.@)
2594 BOOL WINAPI IsChild( HWND parent, HWND child )
2596 HWND *list = WIN_ListParents( child );
2600 if (!list) return FALSE;
2601 parent = WIN_GetFullHandle( parent );
2602 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2603 ret = (list[i] != 0);
2604 HeapFree( GetProcessHeap(), 0, list );
2609 /***********************************************************************
2610 * IsWindowVisible (USER32.@)
2612 BOOL WINAPI IsWindowVisible( HWND hwnd )
2618 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2619 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2620 for (i = 0; list[i]; i++)
2621 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2623 HeapFree( GetProcessHeap(), 0, list );
2628 /***********************************************************************
2629 * WIN_IsWindowDrawable
2631 * hwnd is drawable when it is visible, all parents are not
2632 * minimized, and it is itself not minimized unless we are
2633 * trying to draw its default class icon.
2635 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2640 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2642 if (!(style & WS_VISIBLE)) return FALSE;
2643 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2645 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2646 for (i = 0; list[i]; i++)
2647 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2650 HeapFree( GetProcessHeap(), 0, list );
2655 /*******************************************************************
2656 * GetTopWindow (USER32.@)
2658 HWND WINAPI GetTopWindow( HWND hwnd )
2660 if (!hwnd) hwnd = GetDesktopWindow();
2661 return GetWindow( hwnd, GW_CHILD );
2665 /*******************************************************************
2666 * GetWindow (USER32.@)
2668 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2672 if (rel == GW_OWNER) /* this one may be available locally */
2674 WND *wndPtr = WIN_GetPtr( hwnd );
2677 SetLastError( ERROR_INVALID_HANDLE );
2680 if (wndPtr != WND_OTHER_PROCESS)
2682 retval = wndPtr->owner;
2683 WIN_ReleasePtr( wndPtr );
2686 /* else fall through to server call */
2689 SERVER_START_REQ( get_window_tree )
2692 if (!wine_server_call_err( req ))
2697 retval = reply->first_sibling;
2700 retval = reply->last_sibling;
2703 retval = reply->next_sibling;
2706 retval = reply->prev_sibling;
2709 retval = reply->owner;
2712 retval = reply->first_child;
2722 /***********************************************************************
2723 * WIN_InternalShowOwnedPopups
2725 * Internal version of ShowOwnedPopups; Wine functions should use this
2726 * to avoid interfering with application calls to ShowOwnedPopups
2727 * and to make sure the application can't prevent showing/hiding.
2729 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2733 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2737 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2739 if (!win_array) return TRUE;
2742 * Show windows Lowest first, Highest last to preserve Z-Order
2744 while (win_array[count]) count++;
2745 while (--count >= 0)
2747 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2748 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2750 if (pWnd->dwStyle & WS_POPUP)
2754 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2755 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2758 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2760 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2761 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2766 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2767 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2768 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2771 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2773 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2774 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2775 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2779 WIN_ReleaseWndPtr( pWnd );
2781 HeapFree( GetProcessHeap(), 0, win_array );
2786 /*******************************************************************
2787 * ShowOwnedPopups (USER32.@)
2789 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2793 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2795 if (!win_array) return TRUE;
2797 while (win_array[count]) count++;
2798 while (--count >= 0)
2800 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2801 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2803 if (pWnd->dwStyle & WS_POPUP)
2807 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2809 /* In Windows, ShowOwnedPopups(TRUE) generates
2810 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2811 * regardless of the state of the owner
2813 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2814 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2819 if (IsWindowVisible(pWnd->hwndSelf))
2821 /* In Windows, ShowOwnedPopups(FALSE) generates
2822 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2823 * regardless of the state of the owner
2825 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2826 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2830 WIN_ReleaseWndPtr( pWnd );
2832 HeapFree( GetProcessHeap(), 0, win_array );
2837 /*******************************************************************
2838 * GetLastActivePopup (USER32.@)
2840 HWND WINAPI GetLastActivePopup( HWND hwnd )
2844 SERVER_START_REQ( get_window_info )
2847 if (!wine_server_call_err( req )) retval = reply->last_active;
2854 /*******************************************************************
2857 * Build an array of all parents of a given window, starting with
2858 * the immediate parent. The array must be freed with HeapFree.
2859 * Returns NULL if window is a top-level window.
2861 HWND *WIN_ListParents( HWND hwnd )
2864 HWND current, *list;
2865 int pos = 0, size = 16, count = 0;
2867 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2872 if (!(win = WIN_GetPtr( current ))) goto empty;
2873 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2874 list[pos] = win->parent;
2875 WIN_ReleasePtr( win );
2876 if (!(current = list[pos]))
2878 if (!pos) goto empty;
2881 if (++pos == size - 1)
2883 /* need to grow the list */
2884 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2885 if (!new_list) goto empty;
2891 /* at least one parent belongs to another process, have to query the server */
2896 SERVER_START_REQ( get_window_parents )
2899 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2900 if (!wine_server_call( req )) count = reply->count;
2903 if (!count) goto empty;
2909 HeapFree( GetProcessHeap(), 0, list );
2911 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2915 HeapFree( GetProcessHeap(), 0, list );
2920 /*******************************************************************
2923 * Build an array of the children of a given window. The array must be
2924 * freed with HeapFree. Returns NULL when no windows are found.
2926 HWND *WIN_ListChildren( HWND hwnd )
2928 return list_window_children( hwnd, 0, 0 );
2932 /*******************************************************************
2933 * EnumWindows (USER32.@)
2935 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2941 /* We have to build a list of all windows first, to avoid */
2942 /* unpleasant side-effects, for instance if the callback */
2943 /* function changes the Z-order of the windows. */
2945 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2947 /* Now call the callback function for every window */
2949 iWndsLocks = WIN_SuspendWndsLock();
2950 for (i = 0; list[i]; i++)
2952 /* Make sure that the window still exists */
2953 if (!IsWindow( list[i] )) continue;
2954 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2956 WIN_RestoreWndsLock(iWndsLocks);
2957 HeapFree( GetProcessHeap(), 0, list );
2962 /**********************************************************************
2963 * EnumThreadWindows (USER32.@)
2965 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2970 if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
2972 /* Now call the callback function for every window */
2974 iWndsLocks = WIN_SuspendWndsLock();
2975 for (i = 0; list[i]; i++)
2976 if (!func( list[i], lParam )) break;
2977 WIN_RestoreWndsLock(iWndsLocks);
2978 HeapFree( GetProcessHeap(), 0, list );
2983 /**********************************************************************
2984 * WIN_EnumChildWindows
2986 * Helper function for EnumChildWindows().
2988 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2993 for ( ; *list; list++)
2995 /* Make sure that the window still exists */
2996 if (!IsWindow( *list )) continue;
2997 /* skip owned windows */
2998 if (GetWindow( *list, GW_OWNER )) continue;
2999 /* Build children list first */
3000 childList = WIN_ListChildren( *list );
3002 ret = func( *list, lParam );
3006 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3007 HeapFree( GetProcessHeap(), 0, childList );
3009 if (!ret) return FALSE;
3015 /**********************************************************************
3016 * EnumChildWindows (USER32.@)
3018 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3023 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3024 iWndsLocks = WIN_SuspendWndsLock();
3025 WIN_EnumChildWindows( list, func, lParam );
3026 WIN_RestoreWndsLock(iWndsLocks);
3027 HeapFree( GetProcessHeap(), 0, list );
3032 /*******************************************************************
3033 * AnyPopup (USER.52)
3035 BOOL16 WINAPI AnyPopup16(void)
3041 /*******************************************************************
3042 * AnyPopup (USER32.@)
3044 BOOL WINAPI AnyPopup(void)
3048 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3050 if (!list) return FALSE;
3051 for (i = 0; list[i]; i++)
3053 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3055 retvalue = (list[i] != 0);
3056 HeapFree( GetProcessHeap(), 0, list );
3061 /*******************************************************************
3062 * FlashWindow (USER32.@)
3064 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3066 WND *wndPtr = WIN_FindWndPtr(hWnd);
3068 TRACE("%p\n", hWnd);
3070 if (!wndPtr) return FALSE;
3071 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3073 if (wndPtr->dwStyle & WS_MINIMIZE)
3075 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3077 HDC hDC = GetDC(hWnd);
3079 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 ))
3080 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3082 ReleaseDC( hWnd, hDC );
3083 wndPtr->flags |= WIN_NCACTIVATED;
3087 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3088 wndPtr->flags &= ~WIN_NCACTIVATED;
3090 WIN_ReleaseWndPtr(wndPtr);
3096 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3097 else wparam = (hWnd == GetForegroundWindow());
3099 WIN_ReleaseWndPtr(wndPtr);
3100 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3106 /*******************************************************************
3107 * GetWindowContextHelpId (USER32.@)
3109 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3112 WND *wnd = WIN_FindWndPtr( hwnd );
3114 retval = wnd->helpContext;
3115 WIN_ReleaseWndPtr(wnd);
3120 /*******************************************************************
3121 * SetWindowContextHelpId (USER32.@)
3123 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3125 WND *wnd = WIN_FindWndPtr( hwnd );
3126 if (!wnd) return FALSE;
3127 wnd->helpContext = id;
3128 WIN_ReleaseWndPtr(wnd);
3133 /*******************************************************************
3134 * DragDetect (USER32.@)
3136 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3141 rect.left = pt.x - wDragWidth;
3142 rect.right = pt.x + wDragWidth;
3144 rect.top = pt.y - wDragHeight;
3145 rect.bottom = pt.y + wDragHeight;
3151 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3153 if( msg.message == WM_LBUTTONUP )
3158 if( msg.message == WM_MOUSEMOVE )
3161 tmp.x = LOWORD(msg.lParam);
3162 tmp.y = HIWORD(msg.lParam);
3163 if( !PtInRect( &rect, tmp ))
3175 /******************************************************************************
3176 * GetWindowModuleFileNameA (USER32.@)
3178 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3180 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3181 hwnd, lpszFileName, cchFileNameMax);
3185 /******************************************************************************
3186 * GetWindowModuleFileNameW (USER32.@)
3188 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3190 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3191 hwnd, lpszFileName, cchFileNameMax);
3195 /******************************************************************************
3196 * GetWindowInfo (USER32.@)
3199 * MS Documentation mentions that pwi->cbSize must be set to SIZEOF(WINDOWINFO)
3200 * this may be because this structure changed over time. If this is the
3201 * the case, then please: FIXME.
3202 * Using the structure described in MSDN for 98/ME/NT(4.0 SP3)/2000/XP.
3204 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3206 WND *wndInfo = NULL;
3207 if (!pwi) return FALSE;
3208 if (pwi->cbSize != sizeof(WINDOWINFO))
3210 FIXME("windowinfo->cbSize != sizeof(WINDOWINFO). Please report\n");
3213 wndInfo = WIN_GetPtr(hwnd);
3214 if (!wndInfo) return FALSE;
3215 if (wndInfo == WND_OTHER_PROCESS)
3217 FIXME("window belong to other process\n");
3221 pwi->rcWindow = wndInfo->rectWindow;
3222 pwi->rcClient = wndInfo->rectClient;
3223 pwi->dwStyle = wndInfo->dwStyle;
3224 pwi->dwExStyle = wndInfo->dwExStyle;
3225 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3226 /* if active WS_ACTIVECAPTION, else 0 */
3228 pwi->cxWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3229 GetSystemMetrics(SM_CXBORDER) : 0);
3230 pwi->cyWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3231 GetSystemMetrics(SM_CYBORDER) : 0);
3232 /* above two: I'm presuming that borders widths are the same
3233 * for each window - so long as its actually using a border.. */
3235 pwi->atomWindowType = GetClassLongA( hwnd, GCW_ATOM );
3236 pwi->wCreatorVersion = GetVersion();
3237 /* Docs say this should be the version that
3238 * CREATED the window. But eh?.. Isn't that just the
3239 * version we are running.. Unless ofcourse its some wacky
3240 * RPC stuff or something */
3242 WIN_ReleasePtr(wndInfo);