2 * Window related functions
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
28 #include "wine/winbase16.h"
29 #include "wine/winuser16.h"
30 #include "wine/server.h"
31 #include "wine/unicode.h"
36 #include "cursoricon.h"
43 #include "stackframe.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(win);
47 WINE_DECLARE_DEBUG_CHANNEL(msg);
49 #define NB_USER_HANDLES (LAST_USER_HANDLE - FIRST_USER_HANDLE + 1)
51 /**********************************************************************/
54 static WND *pWndDesktop = NULL;
56 static WORD wDragWidth = 4;
57 static WORD wDragHeight= 3;
59 static void *user_handles[NB_USER_HANDLES];
62 extern SYSLEVEL USER_SysLevel; /* FIXME */
64 /***********************************************************************
67 * Suspend the lock on WND structures.
68 * Returns the number of locks suspended
70 int WIN_SuspendWndsLock( void )
72 int isuspendedLocks = _ConfirmSysLevel( &USER_SysLevel );
73 int count = isuspendedLocks;
76 _LeaveSysLevel( &USER_SysLevel );
78 return isuspendedLocks;
81 /***********************************************************************
84 * Restore the suspended locks on WND structures
86 void WIN_RestoreWndsLock( int ipreviousLocks )
88 while ( ipreviousLocks-- > 0 )
89 _EnterSysLevel( &USER_SysLevel );
92 /***********************************************************************
93 * create_window_handle
95 * Create a window handle with the server.
97 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, INT size )
100 user_handle_t handle = 0;
102 WND *win = HeapAlloc( GetProcessHeap(), 0, size );
104 if (!win) return NULL;
108 SERVER_START_REQ( create_window )
110 req->parent = parent;
113 if ((res = !wine_server_call_err( req ))) handle = reply->handle;
120 HeapFree( GetProcessHeap(), 0, win );
123 index = LOWORD(handle) - FIRST_USER_HANDLE;
124 assert( index < NB_USER_HANDLES );
125 user_handles[index] = win;
126 win->hwndSelf = handle;
127 win->dwMagic = WND_MAGIC;
133 /***********************************************************************
136 * Free a window handle.
138 static WND *free_window_handle( HWND hwnd )
141 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
143 if (index >= NB_USER_HANDLES) return NULL;
145 if ((ptr = user_handles[index]))
147 SERVER_START_REQ( destroy_window )
150 if (!wine_server_call_err( req ))
151 user_handles[index] = NULL;
158 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
163 /*******************************************************************
164 * list_window_children
166 * Build an array of the children of a given window. The array must be
167 * freed with HeapFree. Returns NULL when no windows are found.
169 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
178 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
180 SERVER_START_REQ( get_window_children )
184 req->tid = (void *)tid;
185 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
186 if (!wine_server_call( req )) count = reply->count;
189 if (count && count < size)
194 HeapFree( GetProcessHeap(), 0, list );
196 size = count + 1; /* restart with a large enough buffer */
202 /*******************************************************************
205 static void send_parent_notify( HWND hwnd, UINT msg )
207 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) return;
208 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) return;
209 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
210 MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
214 /*******************************************************************
215 * get_server_window_text
217 * Retrieve the window text from the server.
219 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
223 SERVER_START_REQ( get_window_text )
226 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
227 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
230 text[len / sizeof(WCHAR)] = 0;
234 /***********************************************************************
237 * Return a pointer to the WND structure if local to the process,
238 * or WND_OTHER_PROCESS is handle may be valid in other process.
239 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
241 WND *WIN_GetPtr( HWND hwnd )
244 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
246 if (index >= NB_USER_HANDLES) return NULL;
249 if ((ptr = user_handles[index]))
251 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
255 else ptr = WND_OTHER_PROCESS;
261 /***********************************************************************
262 * WIN_IsCurrentProcess
264 * Check whether a given window belongs to the current process (and return the full handle).
266 HWND WIN_IsCurrentProcess( HWND hwnd )
271 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
273 WIN_ReleasePtr( ptr );
278 /***********************************************************************
279 * WIN_IsCurrentThread
281 * Check whether a given window belongs to the current thread (and return the full handle).
283 HWND WIN_IsCurrentThread( HWND hwnd )
288 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
290 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
291 WIN_ReleasePtr( ptr );
297 /***********************************************************************
300 * Convert a 16-bit window handle to a full 32-bit handle.
302 HWND WIN_Handle32( HWND16 hwnd16 )
305 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
307 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
308 /* do sign extension for -2 and -3 */
309 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
311 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
313 if (ptr != WND_OTHER_PROCESS)
315 hwnd = ptr->hwndSelf;
316 WIN_ReleasePtr( ptr );
318 else /* may belong to another process */
320 SERVER_START_REQ( get_window_info )
323 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
331 /***********************************************************************
334 * Return a pointer to the WND structure corresponding to a HWND.
336 WND * WIN_FindWndPtr( HWND hwnd )
340 if (!hwnd) return NULL;
342 if ((ptr = WIN_GetPtr( hwnd )))
344 if (ptr != WND_OTHER_PROCESS)
346 /* increment destruction monitoring */
350 if (IsWindow( hwnd )) /* check other processes */
352 ERR( "window %04x belongs to other process\n", hwnd );
353 /* DbgBreakPoint(); */
356 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
361 /***********************************************************************
364 * Release the pointer to the WND structure.
366 void WIN_ReleaseWndPtr(WND *wndPtr)
370 /* Decrement destruction monitoring value */
372 /* Check if it's time to release the memory */
373 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
376 free_window_handle( wndPtr->hwndSelf );
378 else if(wndPtr->irefCount < 0)
380 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
381 ERR("forgot a Lock on %p somewhere\n",wndPtr);
383 /* unlock all WND structures for thread safeness */
388 /***********************************************************************
391 * Remove a window from the siblings linked list.
393 void WIN_UnlinkWindow( HWND hwnd )
395 WIN_LinkWindow( hwnd, 0, 0 );
399 /***********************************************************************
402 * Insert a window into the siblings linked list.
403 * The window is inserted after the specified window, which can also
404 * be specified as HWND_TOP or HWND_BOTTOM.
405 * If parent is 0, window is unlinked from the tree.
407 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
409 WND *wndPtr = WIN_GetPtr( hwnd );
412 if (wndPtr == WND_OTHER_PROCESS)
414 if (IsWindow(hwnd)) ERR(" cannot link other process window %x\n", hwnd );
418 SERVER_START_REQ( link_window )
421 req->parent = parent;
422 req->previous = hwndInsertAfter;
423 if (!wine_server_call( req ))
425 if (reply->full_parent && reply->full_parent != wndPtr->parent)
427 wndPtr->owner = 0; /* reset owner when changing parent */
428 wndPtr->parent = reply->full_parent;
434 WIN_ReleasePtr( wndPtr );
438 /***********************************************************************
441 * Change the owner of a window.
443 void WIN_SetOwner( HWND hwnd, HWND owner )
445 WND *win = WIN_GetPtr( hwnd );
448 if (win == WND_OTHER_PROCESS)
450 if (IsWindow(hwnd)) ERR( "cannot set owner %x on other process window %x\n", owner, hwnd );
453 SERVER_START_REQ( set_window_owner )
457 if (!wine_server_call( req )) win->owner = reply->full_owner;
460 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 %x\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 %x\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 %x\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 %x 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("%04x\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;
685 wndPtr->hmemTaskQ = 0;
687 if (!(wndPtr->dwStyle & WS_CHILD))
689 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
690 if (menu) DestroyMenu( menu );
692 if (wndPtr->hSysMenu)
694 DestroyMenu( wndPtr->hSysMenu );
695 wndPtr->hSysMenu = 0;
697 USER_Driver.pDestroyWindow( hwnd );
698 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
699 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
700 CLASS_RemoveWindow( wndPtr->class );
701 wndPtr->class = NULL;
702 wndPtr->dwMagic = 0; /* Mark it as invalid */
703 WIN_ReleaseWndPtr( wndPtr );
707 /***********************************************************************
708 * WIN_DestroyThreadWindows
710 * Destroy all children of 'wnd' owned by the current thread.
711 * Return TRUE if something was done.
713 void WIN_DestroyThreadWindows( HWND hwnd )
718 if (!(list = WIN_ListChildren( hwnd ))) return;
719 for (i = 0; list[i]; i++)
721 if (WIN_IsCurrentThread( list[i] ))
722 DestroyWindow( list[i] );
724 WIN_DestroyThreadWindows( list[i] );
726 HeapFree( GetProcessHeap(), 0, list );
729 /***********************************************************************
730 * WIN_CreateDesktopWindow
732 * Create the desktop window.
734 BOOL WIN_CreateDesktopWindow(void)
736 struct tagCLASS *class;
745 TRACE("Creating desktop window\n");
747 if (!WINPOS_CreateInternalPosAtom() ||
748 !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
749 &wndExtra, &winproc, &clsStyle, &dce )))
752 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM),
753 sizeof(WND) + wndExtra - sizeof(pWndDesktop->wExtra) );
754 if (!pWndDesktop) return FALSE;
755 hwndDesktop = pWndDesktop->hwndSelf;
757 pWndDesktop->tid = 0; /* nobody owns the desktop */
758 pWndDesktop->parent = 0;
759 pWndDesktop->owner = 0;
760 pWndDesktop->class = class;
761 pWndDesktop->hInstance = 0;
762 pWndDesktop->text = NULL;
763 pWndDesktop->hmemTaskQ = 0;
764 pWndDesktop->hrgnUpdate = 0;
765 pWndDesktop->hwndLastActive = hwndDesktop;
766 pWndDesktop->dwStyle = 0;
767 pWndDesktop->dwExStyle = 0;
768 pWndDesktop->clsStyle = clsStyle;
769 pWndDesktop->dce = NULL;
770 pWndDesktop->pVScroll = NULL;
771 pWndDesktop->pHScroll = NULL;
772 pWndDesktop->wIDmenu = 0;
773 pWndDesktop->helpContext = 0;
774 pWndDesktop->flags = 0;
775 pWndDesktop->hSysMenu = 0;
776 pWndDesktop->userdata = 0;
777 pWndDesktop->winproc = winproc;
778 pWndDesktop->cbWndExtra = wndExtra;
780 cs.lpCreateParams = NULL;
786 cs.cx = GetSystemMetrics( SM_CXSCREEN );
787 cs.cy = GetSystemMetrics( SM_CYSCREEN );
788 cs.style = pWndDesktop->dwStyle;
789 cs.dwExStyle = pWndDesktop->dwExStyle;
791 cs.lpszClass = DESKTOP_CLASS_ATOM;
793 SetRect( &rect, 0, 0, cs.cx, cs.cy );
794 WIN_SetRectangles( hwndDesktop, &rect, &rect );
795 WIN_SetStyle( hwndDesktop, WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
797 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
799 WIN_ReleaseWndPtr( pWndDesktop );
803 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
804 WIN_ReleaseWndPtr( pWndDesktop );
809 /***********************************************************************
812 * Fix the coordinates - Helper for WIN_CreateWindowEx.
813 * returns default show mode in sw.
814 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
816 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
818 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
819 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
821 if (cs->style & (WS_CHILD | WS_POPUP))
823 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
824 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
826 else /* overlapped window */
830 GetStartupInfoA( &info );
832 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
834 /* Never believe Microsoft's documentation... CreateWindowEx doc says
835 * that if an overlapped window is created with WS_VISIBLE style bit
836 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
837 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
840 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
841 * 2) it does not ignore the y parameter as the docs claim; instead, it
842 * uses it as second parameter to ShowWindow() unless y is either
843 * CW_USEDEFAULT or CW_USEDEFAULT16.
845 * The fact that we didn't do 2) caused bogus windows pop up when wine
846 * was running apps that were using this obscure feature. Example -
847 * calc.exe that comes with Win98 (only Win98, it's different from
848 * the one that comes with Win95 and NT)
850 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
851 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
852 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
855 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
857 if (info.dwFlags & STARTF_USESIZE)
859 cs->cx = info.dwXSize;
860 cs->cy = info.dwYSize;
862 else /* if no other hint from the app, pick 3/4 of the screen real estate */
865 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
866 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
867 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
874 /* neither x nor cx are default. Check the y values .
875 * In the trace we see Outlook and Outlook Express using
876 * cy set to CW_USEDEFAULT when opening the address book.
878 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
880 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
881 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
882 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
887 /***********************************************************************
890 static void dump_window_styles( DWORD style, DWORD exstyle )
893 if(style & WS_POPUP) DPRINTF(" WS_POPUP");
894 if(style & WS_CHILD) DPRINTF(" WS_CHILD");
895 if(style & WS_MINIMIZE) DPRINTF(" WS_MINIMIZE");
896 if(style & WS_VISIBLE) DPRINTF(" WS_VISIBLE");
897 if(style & WS_DISABLED) DPRINTF(" WS_DISABLED");
898 if(style & WS_CLIPSIBLINGS) DPRINTF(" WS_CLIPSIBLINGS");
899 if(style & WS_CLIPCHILDREN) DPRINTF(" WS_CLIPCHILDREN");
900 if(style & WS_MAXIMIZE) DPRINTF(" WS_MAXIMIZE");
901 if((style & WS_CAPTION) == WS_CAPTION) DPRINTF(" WS_CAPTION");
904 if(style & WS_BORDER) DPRINTF(" WS_BORDER");
905 if(style & WS_DLGFRAME) DPRINTF(" WS_DLGFRAME");
907 if(style & WS_VSCROLL) DPRINTF(" WS_VSCROLL");
908 if(style & WS_HSCROLL) DPRINTF(" WS_HSCROLL");
909 if(style & WS_SYSMENU) DPRINTF(" WS_SYSMENU");
910 if(style & WS_THICKFRAME) DPRINTF(" WS_THICKFRAME");
911 if(style & WS_GROUP) DPRINTF(" WS_GROUP");
912 if(style & WS_TABSTOP) DPRINTF(" WS_TABSTOP");
913 if(style & WS_MINIMIZEBOX) DPRINTF(" WS_MINIMIZEBOX");
914 if(style & WS_MAXIMIZEBOX) DPRINTF(" WS_MAXIMIZEBOX");
916 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
917 #define DUMPED_STYLES \
937 if(style & ~DUMPED_STYLES) DPRINTF(" %08lx", style & ~DUMPED_STYLES);
942 if(exstyle & WS_EX_DLGMODALFRAME) DPRINTF(" WS_EX_DLGMODALFRAME");
943 if(exstyle & WS_EX_DRAGDETECT) DPRINTF(" WS_EX_DRAGDETECT");
944 if(exstyle & WS_EX_NOPARENTNOTIFY) DPRINTF(" WS_EX_NOPARENTNOTIFY");
945 if(exstyle & WS_EX_TOPMOST) DPRINTF(" WS_EX_TOPMOST");
946 if(exstyle & WS_EX_ACCEPTFILES) DPRINTF(" WS_EX_ACCEPTFILES");
947 if(exstyle & WS_EX_TRANSPARENT) DPRINTF(" WS_EX_TRANSPARENT");
948 if(exstyle & WS_EX_MDICHILD) DPRINTF(" WS_EX_MDICHILD");
949 if(exstyle & WS_EX_TOOLWINDOW) DPRINTF(" WS_EX_TOOLWINDOW");
950 if(exstyle & WS_EX_WINDOWEDGE) DPRINTF(" WS_EX_WINDOWEDGE");
951 if(exstyle & WS_EX_CLIENTEDGE) DPRINTF(" WS_EX_CLIENTEDGE");
952 if(exstyle & WS_EX_CONTEXTHELP) DPRINTF(" WS_EX_CONTEXTHELP");
953 if(exstyle & WS_EX_RIGHT) DPRINTF(" WS_EX_RIGHT");
954 if(exstyle & WS_EX_RTLREADING) DPRINTF(" WS_EX_RTLREADING");
955 if(exstyle & WS_EX_LEFTSCROLLBAR) DPRINTF(" WS_EX_LEFTSCROLLBAR");
956 if(exstyle & WS_EX_CONTROLPARENT) DPRINTF(" WS_EX_CONTROLPARENT");
957 if(exstyle & WS_EX_STATICEDGE) DPRINTF(" WS_EX_STATICEDGE");
958 if(exstyle & WS_EX_APPWINDOW) DPRINTF(" WS_EX_APPWINDOW");
959 if(exstyle & WS_EX_LAYERED) DPRINTF(" WS_EX_LAYERED");
961 #define DUMPED_EX_STYLES \
962 (WS_EX_DLGMODALFRAME | \
964 WS_EX_NOPARENTNOTIFY | \
966 WS_EX_ACCEPTFILES | \
967 WS_EX_TRANSPARENT | \
972 WS_EX_CONTEXTHELP | \
975 WS_EX_LEFTSCROLLBAR | \
976 WS_EX_CONTROLPARENT | \
981 if(exstyle & ~DUMPED_EX_STYLES) DPRINTF(" %08lx", exstyle & ~DUMPED_EX_STYLES);
983 #undef DUMPED_EX_STYLES
987 /***********************************************************************
990 * Implementation of CreateWindowEx().
992 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
993 WINDOWPROCTYPE type )
996 struct tagCLASS *classPtr;
998 HWND hwnd, parent, owner;
1003 BOOL unicode = (type == WIN_PROC_32W);
1005 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%04x menu=%04x inst=%08x params=%p\n",
1006 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1007 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
1008 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1009 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1011 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1013 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1014 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1016 /* Find the parent window */
1018 parent = GetDesktopWindow();
1022 /* Make sure parent is valid */
1023 if (!IsWindow( cs->hwndParent ))
1025 WARN("Bad parent %04x\n", cs->hwndParent );
1028 if (cs->style & WS_CHILD) parent = WIN_GetFullHandle(cs->hwndParent);
1029 else owner = GetAncestor( cs->hwndParent, GA_ROOT );
1031 else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP))
1033 WARN("No parent for child window\n" );
1034 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1037 /* Find the window class */
1038 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
1039 &wndExtra, &winproc, &clsStyle, &dce )))
1041 WARN("Bad class '%s'\n", cs->lpszClass );
1045 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1047 /* Correct the window style - stage 1
1049 * These are patches that appear to affect both the style loaded into the
1050 * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
1052 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1053 * why does the user get to set it?
1056 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1057 * tested for WS_POPUP
1059 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1060 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1061 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1062 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1064 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1066 /* Create the window structure */
1068 if (!(wndPtr = create_window_handle( parent, owner, classAtom,
1069 sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
1071 TRACE("out of memory\n" );
1074 hwnd = wndPtr->hwndSelf;
1076 /* Fill the window structure */
1078 wndPtr->tid = GetCurrentThreadId();
1079 wndPtr->owner = owner;
1080 wndPtr->parent = parent;
1081 wndPtr->class = classPtr;
1082 wndPtr->winproc = winproc;
1083 wndPtr->hInstance = cs->hInstance;
1084 wndPtr->text = NULL;
1085 wndPtr->hmemTaskQ = InitThreadInput16( 0, 0 );
1086 wndPtr->hrgnUpdate = 0;
1087 wndPtr->hrgnWnd = 0;
1088 wndPtr->hwndLastActive = hwnd;
1089 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1090 wndPtr->dwExStyle = cs->dwExStyle;
1091 wndPtr->clsStyle = clsStyle;
1092 wndPtr->wIDmenu = 0;
1093 wndPtr->helpContext = 0;
1094 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1095 wndPtr->pVScroll = NULL;
1096 wndPtr->pHScroll = NULL;
1097 wndPtr->userdata = 0;
1098 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU)
1099 ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1100 wndPtr->cbWndExtra = wndExtra;
1102 if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
1104 /* Correct the window style - stage 2 */
1106 if (!(cs->style & WS_CHILD))
1108 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1109 if (!(cs->style & WS_POPUP))
1111 wndPtr->dwStyle |= WS_CAPTION;
1112 wndPtr->flags |= WIN_NEED_SIZE;
1115 SERVER_START_REQ( set_window_info )
1118 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1119 req->style = wndPtr->dwStyle;
1120 req->ex_style = wndPtr->dwExStyle;
1121 req->instance = (void *)wndPtr->hInstance;
1122 wine_server_call( req );
1126 /* Get class or window DC if needed */
1128 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1129 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
1130 else wndPtr->dce = NULL;
1132 /* Set the window menu */
1134 if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
1136 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1139 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1142 if (HIWORD(cs->hInstance))
1143 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1145 cs->hMenu = LoadMenu16(cs->hInstance,menuName);
1147 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1151 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1152 WIN_ReleaseWndPtr( wndPtr );
1154 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1156 WIN_DestroyWindow( hwnd );
1160 /* Notify the parent window only */
1162 send_parent_notify( hwnd, WM_CREATE );
1163 if (!IsWindow( hwnd )) return 0;
1165 if (cs->style & WS_VISIBLE)
1167 /* in case WS_VISIBLE got set in the meantime */
1168 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1169 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1170 WIN_ReleasePtr( wndPtr );
1171 ShowWindow( hwnd, sw );
1174 /* Call WH_SHELL hook */
1176 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1177 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
1179 TRACE("created window %04x\n", hwnd);
1184 /***********************************************************************
1185 * CreateWindow (USER.41)
1187 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1188 DWORD style, INT16 x, INT16 y, INT16 width,
1189 INT16 height, HWND16 parent, HMENU16 menu,
1190 HINSTANCE16 instance, LPVOID data )
1192 return CreateWindowEx16( 0, className, windowName, style,
1193 x, y, width, height, parent, menu, instance, data );
1197 /***********************************************************************
1198 * CreateWindowEx (USER.452)
1200 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1201 LPCSTR windowName, DWORD style, INT16 x,
1202 INT16 y, INT16 width, INT16 height,
1203 HWND16 parent, HMENU16 menu,
1204 HINSTANCE16 instance, LPVOID data )
1210 /* Find the class atom */
1212 if (HIWORD(className))
1214 if (!(classAtom = GlobalFindAtomA( className )))
1216 ERR( "bad class name %s\n", debugstr_a(className) );
1222 classAtom = LOWORD(className);
1223 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1225 ERR( "bad atom %x\n", classAtom);
1231 /* Fix the coordinates */
1233 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1234 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1235 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1236 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1238 /* Create the window */
1240 cs.lpCreateParams = data;
1241 cs.hInstance = (HINSTANCE)instance;
1242 cs.hMenu = (HMENU)menu;
1243 cs.hwndParent = WIN_Handle32( parent );
1245 cs.lpszName = windowName;
1246 cs.lpszClass = className;
1247 cs.dwExStyle = exStyle;
1249 return WIN_Handle16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1253 /***********************************************************************
1254 * CreateWindowExA (USER32.@)
1256 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1257 LPCSTR windowName, DWORD style, INT x,
1258 INT y, INT width, INT height,
1259 HWND parent, HMENU menu,
1260 HINSTANCE instance, LPVOID data )
1267 instance=GetModuleHandleA(NULL);
1269 if(exStyle & WS_EX_MDICHILD)
1270 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1272 /* Find the class atom */
1274 if (HIWORD(className))
1276 if (!(classAtom = GlobalFindAtomA( className )))
1278 ERR( "bad class name %s\n", debugstr_a(className) );
1284 classAtom = LOWORD(className);
1285 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1287 ERR( "bad atom %x\n", classAtom);
1293 /* Create the window */
1295 cs.lpCreateParams = data;
1296 cs.hInstance = instance;
1298 cs.hwndParent = parent;
1304 cs.lpszName = windowName;
1305 cs.lpszClass = className;
1306 cs.dwExStyle = exStyle;
1308 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1312 /***********************************************************************
1313 * CreateWindowExW (USER32.@)
1315 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1316 LPCWSTR windowName, DWORD style, INT x,
1317 INT y, INT width, INT height,
1318 HWND parent, HMENU menu,
1319 HINSTANCE instance, LPVOID data )
1326 instance=GetModuleHandleA(NULL);
1328 if(exStyle & WS_EX_MDICHILD)
1329 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1331 /* Find the class atom */
1333 if (HIWORD(className))
1335 if (!(classAtom = GlobalFindAtomW( className )))
1337 ERR( "bad class name %s\n", debugstr_w(className) );
1343 classAtom = LOWORD(className);
1344 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1346 ERR( "bad atom %x\n", classAtom);
1352 /* Create the window */
1354 cs.lpCreateParams = data;
1355 cs.hInstance = instance;
1357 cs.hwndParent = parent;
1363 cs.lpszName = windowName;
1364 cs.lpszClass = className;
1365 cs.dwExStyle = exStyle;
1367 /* Note: we rely on the fact that CREATESTRUCTA and */
1368 /* CREATESTRUCTW have the same layout. */
1369 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1373 /***********************************************************************
1374 * WIN_SendDestroyMsg
1376 static void WIN_SendDestroyMsg( HWND hwnd )
1378 if( CARET_GetHwnd() == hwnd) DestroyCaret();
1379 if (USER_Driver.pResetSelectionOwner)
1380 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1383 * Send the WM_DESTROY to the window.
1385 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1388 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1389 * make sure that the window still exists when we come back.
1396 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1398 /* start from the end (FIXME: is this needed?) */
1399 for (i = 0; pWndArray[i]; i++) ;
1403 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1405 HeapFree( GetProcessHeap(), 0, pWndArray );
1408 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1412 /***********************************************************************
1413 * DestroyWindow (USER32.@)
1415 BOOL WINAPI DestroyWindow( HWND hwnd )
1420 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1422 SetLastError( ERROR_ACCESS_DENIED );
1426 TRACE("(%04x)\n", hwnd);
1428 /* Look whether the focus is within the tree of windows we will
1432 if (h == hwnd || IsChild( hwnd, h ))
1434 HWND parent = GetAncestor( hwnd, GA_PARENT );
1435 if (parent == GetDesktopWindow()) parent = 0;
1441 if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
1443 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1447 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1448 send_parent_notify( hwnd, WM_DESTROY );
1450 else if (!GetWindow( hwnd, GW_OWNER ))
1452 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
1453 /* FIXME: clean up palette - see "Internals" p.352 */
1456 if (!IsWindow(hwnd)) return TRUE;
1458 if (USER_Driver.pResetSelectionOwner)
1459 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1461 /* Hide the window */
1463 ShowWindow( hwnd, SW_HIDE );
1464 if (!IsWindow(hwnd)) return TRUE;
1466 /* Recursively destroy owned windows */
1475 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1478 for (i = 0; list[i]; i++)
1480 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1481 if (WIN_IsCurrentThread( list[i] ))
1483 DestroyWindow( list[i] );
1487 WIN_SetOwner( list[i], 0 );
1489 HeapFree( GetProcessHeap(), 0, list );
1491 if (!got_one) break;
1494 WINPOS_ActivateOtherWindow( hwnd );
1496 if ((owner = GetWindow( hwnd, GW_OWNER )))
1498 WND *ptr = WIN_FindWndPtr( owner );
1501 if (ptr->hwndLastActive == hwnd) ptr->hwndLastActive = owner;
1502 WIN_ReleaseWndPtr( ptr );
1507 /* Send destroy messages */
1509 WIN_SendDestroyMsg( hwnd );
1510 if (!IsWindow( hwnd )) return TRUE;
1512 /* Unlink now so we won't bother with the children later on */
1514 WIN_UnlinkWindow( hwnd );
1516 /* Destroy the window storage */
1518 WIN_DestroyWindow( hwnd );
1523 /***********************************************************************
1524 * CloseWindow (USER32.@)
1526 BOOL WINAPI CloseWindow( HWND hwnd )
1528 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1529 ShowWindow( hwnd, SW_MINIMIZE );
1534 /***********************************************************************
1535 * OpenIcon (USER32.@)
1537 BOOL WINAPI OpenIcon( HWND hwnd )
1539 if (!IsIconic( hwnd )) return FALSE;
1540 ShowWindow( hwnd, SW_SHOWNORMAL );
1545 /***********************************************************************
1548 * Implementation of FindWindow() and FindWindowEx().
1550 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1555 WCHAR *buffer = NULL;
1557 if (!parent) parent = GetDesktopWindow();
1560 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1561 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1564 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1568 child = WIN_GetFullHandle( child );
1569 while (list[i] && list[i] != child) i++;
1570 if (!list[i]) goto done;
1571 i++; /* start from next window */
1578 if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1585 if (list) HeapFree( GetProcessHeap(), 0, list );
1586 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1592 /***********************************************************************
1593 * FindWindowA (USER32.@)
1595 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1597 HWND ret = FindWindowExA( 0, 0, className, title );
1598 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1603 /***********************************************************************
1604 * FindWindowExA (USER32.@)
1606 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1607 LPCSTR className, LPCSTR title )
1616 /* If the atom doesn't exist, then no class */
1617 /* with this name exists either. */
1618 if (!(atom = GlobalFindAtomA( className )))
1620 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1624 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1626 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1627 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1628 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1629 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1630 HeapFree( GetProcessHeap(), 0, buffer );
1635 /***********************************************************************
1636 * FindWindowExW (USER32.@)
1638 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1639 LPCWSTR className, LPCWSTR title )
1645 /* If the atom doesn't exist, then no class */
1646 /* with this name exists either. */
1647 if (!(atom = GlobalFindAtomW( className )))
1649 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1653 return WIN_FindWindow( parent, child, atom, title );
1657 /***********************************************************************
1658 * FindWindowW (USER32.@)
1660 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1662 return FindWindowExW( 0, 0, className, title );
1666 /**********************************************************************
1667 * GetDesktopWindow (USER32.@)
1669 HWND WINAPI GetDesktopWindow(void)
1671 if (pWndDesktop) return pWndDesktop->hwndSelf;
1672 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" );
1678 /*******************************************************************
1679 * EnableWindow (USER32.@)
1681 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1688 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1689 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1693 TRACE("( %x, %d )\n", hwnd, enable);
1695 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1696 style = wndPtr->dwStyle;
1697 retvalue = ((style & WS_DISABLED) != 0);
1698 WIN_ReleasePtr( wndPtr );
1700 if (enable && retvalue)
1702 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1703 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1705 else if (!enable && !retvalue)
1707 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1709 WIN_SetStyle( hwnd, style | WS_DISABLED );
1711 if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
1712 SetFocus( 0 ); /* A disabled window can't have the focus */
1714 if (hwnd == GetCapture() || IsChild(hwnd, GetCapture()))
1715 ReleaseCapture(); /* A disabled window can't capture the mouse */
1717 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1723 /***********************************************************************
1724 * IsWindowEnabled (USER32.@)
1726 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1728 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1732 /***********************************************************************
1733 * IsWindowUnicode (USER32.@)
1735 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1740 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1741 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1742 WIN_ReleaseWndPtr(wndPtr);
1747 /**********************************************************************
1748 * GetWindowWord (USER32.@)
1750 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1755 WND *wndPtr = WIN_GetPtr( hwnd );
1758 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1761 if (wndPtr == WND_OTHER_PROCESS)
1763 if (IsWindow( hwnd ))
1764 FIXME( "(%d) not supported yet on other process window %x\n", offset, hwnd );
1765 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1768 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1770 WARN("Invalid offset %d\n", offset );
1771 SetLastError( ERROR_INVALID_INDEX );
1773 else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1774 WIN_ReleasePtr( wndPtr );
1780 case GWL_HWNDPARENT:
1781 return GetWindowLongW( hwnd, offset );
1785 LONG ret = GetWindowLongW( hwnd, offset );
1787 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1791 WARN("Invalid offset %d\n", offset );
1797 /**********************************************************************
1798 * SetWindowWord (USER32.@)
1800 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1809 case GWL_HWNDPARENT:
1810 return SetWindowLongW( hwnd, offset, (UINT)newval );
1814 WARN("Invalid offset %d\n", offset );
1815 SetLastError( ERROR_INVALID_INDEX );
1820 wndPtr = WIN_GetPtr( hwnd );
1821 if (wndPtr == WND_OTHER_PROCESS)
1824 FIXME( "set %d <- %x not supported yet on other process window %x\n",
1825 offset, newval, hwnd );
1830 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1834 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1836 WARN("Invalid offset %d\n", offset );
1837 WIN_ReleasePtr(wndPtr);
1838 SetLastError( ERROR_INVALID_INDEX );
1841 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1844 WIN_ReleasePtr(wndPtr);
1849 /**********************************************************************
1852 * Helper function for GetWindowLong().
1854 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1859 if (offset == GWL_HWNDPARENT) return (LONG)GetParent( hwnd );
1861 if (!(wndPtr = WIN_GetPtr( hwnd )))
1863 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1867 if (wndPtr == WND_OTHER_PROCESS)
1872 FIXME( "(%d) not supported on other process window %x\n", offset, hwnd );
1873 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1876 if (offset == GWL_WNDPROC)
1878 SetLastError( ERROR_ACCESS_DENIED );
1881 SERVER_START_REQ( set_window_info )
1884 req->flags = 0; /* don't set anything, just retrieve */
1885 if (!wine_server_call_err( req ))
1889 case GWL_STYLE: retvalue = reply->old_style; break;
1890 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1891 case GWL_ID: retvalue = reply->old_id; break;
1892 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1893 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1895 SetLastError( ERROR_INVALID_INDEX );
1904 /* now we have a valid wndPtr */
1908 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1911 * Some programs try to access last element from 16 bit
1912 * code using illegal offset value. Hopefully this is
1913 * what those programs really expect.
1915 if (type == WIN_PROC_16 &&
1916 wndPtr->cbWndExtra >= 4 &&
1917 offset == wndPtr->cbWndExtra - sizeof(WORD))
1919 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1921 ERR( "- replaced invalid offset %d with %d\n",
1924 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1925 WIN_ReleasePtr( wndPtr );
1928 WARN("Invalid offset %d\n", offset );
1929 WIN_ReleasePtr( wndPtr );
1930 SetLastError( ERROR_INVALID_INDEX );
1933 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1934 /* Special case for dialog window procedure */
1935 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1936 retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1937 WIN_ReleasePtr( wndPtr );
1943 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
1944 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1945 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1946 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
1947 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1948 case GWL_HINSTANCE: retvalue = wndPtr->hInstance; break;
1950 WARN("Unknown offset %d\n", offset );
1951 SetLastError( ERROR_INVALID_INDEX );
1954 WIN_ReleasePtr(wndPtr);
1959 /**********************************************************************
1962 * Helper function for SetWindowLong().
1964 * 0 is the failure code. However, in the case of failure SetLastError
1965 * must be set to distinguish between a 0 return value and a failure.
1967 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1968 WINDOWPROCTYPE type )
1973 TRACE( "%x %d %lx %x\n", hwnd, offset, newval, type );
1975 if (!WIN_IsCurrentProcess( hwnd ))
1977 if (offset == GWL_WNDPROC)
1979 SetLastError( ERROR_ACCESS_DENIED );
1982 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1985 wndPtr = WIN_GetPtr( hwnd );
1989 LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1990 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1992 WARN("Invalid offset %d\n", offset );
1993 WIN_ReleasePtr( wndPtr );
1994 SetLastError( ERROR_INVALID_INDEX );
1997 /* Special case for dialog window procedure */
1998 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2000 retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
2001 WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
2002 type, WIN_PROC_WINDOW );
2003 WIN_ReleasePtr( wndPtr );
2008 WIN_ReleasePtr( wndPtr );
2015 /* first some special cases */
2020 style.styleOld = wndPtr->dwStyle;
2021 style.styleNew = newval;
2022 WIN_ReleasePtr( wndPtr );
2023 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2024 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2025 newval = style.styleNew;
2027 case GWL_HWNDPARENT:
2028 WIN_ReleasePtr( wndPtr );
2029 return (LONG)SetParent( hwnd, (HWND)newval );
2031 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2032 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
2033 type, WIN_PROC_WINDOW );
2034 WIN_ReleasePtr( wndPtr );
2041 WIN_ReleasePtr( wndPtr );
2042 WARN("Invalid offset %d\n", offset );
2043 SetLastError( ERROR_INVALID_INDEX );
2047 SERVER_START_REQ( set_window_info )
2053 req->flags = SET_WIN_STYLE;
2054 req->style = newval;
2057 req->flags = SET_WIN_EXSTYLE;
2058 req->ex_style = newval;
2061 req->flags = SET_WIN_ID;
2065 req->flags = SET_WIN_INSTANCE;
2066 req->instance = (void *)newval;
2069 req->flags = SET_WIN_USERDATA;
2070 req->user_data = (void *)newval;
2073 if ((ok = !wine_server_call_err( req )))
2078 wndPtr->dwStyle = newval;
2079 retval = reply->old_style;
2082 wndPtr->dwExStyle = newval;
2083 retval = reply->old_ex_style;
2086 wndPtr->wIDmenu = newval;
2087 retval = reply->old_id;
2090 wndPtr->hInstance = newval;
2091 retval = (HINSTANCE)reply->old_instance;
2094 wndPtr->userdata = newval;
2095 retval = (ULONG_PTR)reply->old_user_data;
2101 WIN_ReleasePtr( wndPtr );
2105 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2106 USER_Driver.pSetWindowStyle( hwnd, retval );
2108 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2109 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2116 /**********************************************************************
2117 * GetWindowLong (USER.135)
2119 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2121 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2125 /**********************************************************************
2126 * GetWindowLongA (USER32.@)
2128 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2130 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2134 /**********************************************************************
2135 * GetWindowLongW (USER32.@)
2137 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2139 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2143 /**********************************************************************
2144 * SetWindowLong (USER.136)
2146 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2148 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2152 /**********************************************************************
2153 * SetWindowLongA (USER32.@)
2155 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2157 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2161 /**********************************************************************
2162 * SetWindowLongW (USER32.@) Set window attribute
2164 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2165 * value in a window's extra memory.
2167 * The _hwnd_ parameter specifies the window. is the handle to a
2168 * window that has extra memory. The _newval_ parameter contains the
2169 * new attribute or extra memory value. If positive, the _offset_
2170 * parameter is the byte-addressed location in the window's extra
2171 * memory to set. If negative, _offset_ specifies the window
2172 * attribute to set, and should be one of the following values:
2174 * GWL_EXSTYLE The window's extended window style
2176 * GWL_STYLE The window's window style.
2178 * GWL_WNDPROC Pointer to the window's window procedure.
2180 * GWL_HINSTANCE The window's pplication instance handle.
2182 * GWL_ID The window's identifier.
2184 * GWL_USERDATA The window's user-specified data.
2186 * If the window is a dialog box, the _offset_ parameter can be one of
2187 * the following values:
2189 * DWL_DLGPROC The address of the window's dialog box procedure.
2191 * DWL_MSGRESULT The return value of a message
2192 * that the dialog box procedure processed.
2194 * DWL_USER Application specific information.
2198 * If successful, returns the previous value located at _offset_. Otherwise,
2203 * Extra memory for a window class is specified by a nonzero cbWndExtra
2204 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2205 * time of class creation.
2207 * Using GWL_WNDPROC to set a new window procedure effectively creates
2208 * a window subclass. Use CallWindowProc() in the new windows procedure
2209 * to pass messages to the superclass's window procedure.
2211 * The user data is reserved for use by the application which created
2214 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2215 * instead, call the EnableWindow() function to change the window's
2218 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2219 * SetParent() instead.
2222 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2223 * it sends WM_STYLECHANGING before changing the settings
2224 * and WM_STYLECHANGED afterwards.
2225 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2227 LONG WINAPI SetWindowLongW(
2228 HWND hwnd, /* [in] window to alter */
2229 INT offset, /* [in] offset, in bytes, of location to alter */
2230 LONG newval /* [in] new value of location */
2232 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2236 /*******************************************************************
2237 * GetWindowTextA (USER32.@)
2239 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2243 if (WIN_IsCurrentProcess( hwnd ))
2244 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2246 /* when window belongs to other process, don't send a message */
2247 if (nMaxCount <= 0) return 0;
2248 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2249 get_server_window_text( hwnd, buffer, nMaxCount );
2250 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2251 lpString[nMaxCount-1] = 0;
2252 HeapFree( GetProcessHeap(), 0, buffer );
2253 return strlen(lpString);
2257 /*******************************************************************
2258 * InternalGetWindowText (USER32.@)
2260 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2264 if (nMaxCount <= 0) return 0;
2265 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2266 if (win != WND_OTHER_PROCESS)
2268 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2269 else lpString[0] = 0;
2270 WIN_ReleasePtr( win );
2274 get_server_window_text( hwnd, lpString, nMaxCount );
2276 return strlenW(lpString);
2280 /*******************************************************************
2281 * GetWindowTextW (USER32.@)
2283 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2285 if (WIN_IsCurrentProcess( hwnd ))
2286 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2288 /* when window belongs to other process, don't send a message */
2289 if (nMaxCount <= 0) return 0;
2290 get_server_window_text( hwnd, lpString, nMaxCount );
2291 return strlenW(lpString);
2295 /*******************************************************************
2296 * SetWindowText (USER32.@)
2297 * SetWindowTextA (USER32.@)
2299 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2301 if (!WIN_IsCurrentProcess( hwnd ))
2303 FIXME( "cannot set text %s of other process window %x\n", debugstr_a(lpString), hwnd );
2304 SetLastError( ERROR_ACCESS_DENIED );
2307 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2311 /*******************************************************************
2312 * SetWindowTextW (USER32.@)
2314 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2316 if (!WIN_IsCurrentProcess( hwnd ))
2318 FIXME( "cannot set text %s of other process window %x\n", debugstr_w(lpString), hwnd );
2319 SetLastError( ERROR_ACCESS_DENIED );
2322 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2326 /*******************************************************************
2327 * GetWindowTextLengthA (USER32.@)
2329 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2331 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2334 /*******************************************************************
2335 * GetWindowTextLengthW (USER32.@)
2337 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2339 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2343 /*******************************************************************
2344 * IsWindow (USER32.@)
2346 BOOL WINAPI IsWindow( HWND hwnd )
2351 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2353 if (ptr != WND_OTHER_PROCESS)
2355 WIN_ReleasePtr( ptr );
2359 /* check other processes */
2360 SERVER_START_REQ( get_window_info )
2363 ret = !wine_server_call_err( req );
2370 /***********************************************************************
2371 * GetWindowThreadProcessId (USER32.@)
2373 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2378 if (!(ptr = WIN_GetPtr( hwnd )))
2380 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2384 if (ptr != WND_OTHER_PROCESS)
2386 /* got a valid window */
2388 if (process) *process = GetCurrentProcessId();
2389 WIN_ReleasePtr( ptr );
2393 /* check other processes */
2394 SERVER_START_REQ( get_window_info )
2397 if (!wine_server_call_err( req ))
2399 tid = (DWORD)reply->tid;
2400 if (process) *process = (DWORD)reply->pid;
2408 /*****************************************************************
2409 * GetParent (USER32.@)
2411 HWND WINAPI GetParent( HWND hwnd )
2416 if (!(wndPtr = WIN_GetPtr( hwnd )))
2418 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2421 if (wndPtr == WND_OTHER_PROCESS)
2423 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2424 if (style & (WS_POPUP | WS_CHILD))
2426 SERVER_START_REQ( get_window_tree )
2429 if (!wine_server_call_err( req ))
2431 if (style & WS_CHILD) retvalue = reply->parent;
2432 else retvalue = reply->owner;
2440 if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2441 else if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2442 WIN_ReleasePtr( wndPtr );
2448 /*****************************************************************
2449 * GetAncestor (USER32.@)
2451 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2454 HWND *list, ret = 0;
2456 if (type == GA_PARENT)
2458 if (!(win = WIN_GetPtr( hwnd )))
2460 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2463 if (win != WND_OTHER_PROCESS)
2466 WIN_ReleasePtr( win );
2468 else /* need to query the server */
2470 SERVER_START_REQ( get_window_tree )
2473 if (!wine_server_call_err( req )) ret = reply->parent;
2480 if (!(list = WIN_ListParents( hwnd ))) return 0;
2482 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2486 while (list[count]) count++;
2487 ret = list[count - 2]; /* get the one before the desktop */
2489 HeapFree( GetProcessHeap(), 0, list );
2491 if (ret && type == GA_ROOTOWNER)
2495 HWND owner = GetWindow( ret, GW_OWNER );
2504 /*****************************************************************
2505 * SetParent (USER32.@)
2507 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2510 HWND retvalue, full_handle;
2513 if (!parent) parent = GetDesktopWindow();
2514 else parent = WIN_GetFullHandle( parent );
2516 if (!IsWindow( parent ))
2518 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2522 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2523 return SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2527 if (USER_Driver.pSetParent)
2528 return USER_Driver.pSetParent( hwnd, parent );
2530 /* Windows hides the window first, then shows it again
2531 * including the WM_SHOWWINDOW messages and all */
2532 was_visible = ShowWindow( hwnd, SW_HIDE );
2534 if (!IsWindow( parent )) return 0;
2535 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2537 retvalue = wndPtr->parent; /* old parent */
2538 if (parent != retvalue)
2540 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2542 if (parent != GetDesktopWindow()) /* a child window */
2544 if (!(wndPtr->dwStyle & WS_CHILD))
2546 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2547 if (menu) DestroyMenu( menu );
2551 WIN_ReleasePtr( wndPtr );
2553 /* SetParent additionally needs to make hwnd the topmost window
2554 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2555 WM_WINDOWPOSCHANGED notification messages.
2557 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2558 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2559 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2560 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2565 /*******************************************************************
2566 * IsChild (USER32.@)
2568 BOOL WINAPI IsChild( HWND parent, HWND child )
2570 HWND *list = WIN_ListParents( child );
2574 if (!list) return FALSE;
2575 parent = WIN_GetFullHandle( parent );
2576 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2577 ret = (list[i] != 0);
2578 HeapFree( GetProcessHeap(), 0, list );
2583 /***********************************************************************
2584 * IsWindowVisible (USER32.@)
2586 BOOL WINAPI IsWindowVisible( HWND hwnd )
2592 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2593 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2594 for (i = 0; list[i]; i++)
2595 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2597 HeapFree( GetProcessHeap(), 0, list );
2602 /***********************************************************************
2603 * WIN_IsWindowDrawable
2605 * hwnd is drawable when it is visible, all parents are not
2606 * minimized, and it is itself not minimized unless we are
2607 * trying to draw its default class icon.
2609 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2614 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2616 if (!(style & WS_VISIBLE)) return FALSE;
2617 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) 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|WS_MINIMIZE)) != WS_VISIBLE)
2624 HeapFree( GetProcessHeap(), 0, list );
2629 /*******************************************************************
2630 * GetTopWindow (USER32.@)
2632 HWND WINAPI GetTopWindow( HWND hwnd )
2634 if (!hwnd) hwnd = GetDesktopWindow();
2635 return GetWindow( hwnd, GW_CHILD );
2639 /*******************************************************************
2640 * GetWindow (USER32.@)
2642 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2646 if (rel == GW_OWNER) /* this one may be available locally */
2648 WND *wndPtr = WIN_GetPtr( hwnd );
2651 SetLastError( ERROR_INVALID_HANDLE );
2654 if (wndPtr != WND_OTHER_PROCESS)
2656 retval = wndPtr->owner;
2657 WIN_ReleasePtr( wndPtr );
2660 /* else fall through to server call */
2663 SERVER_START_REQ( get_window_tree )
2666 if (!wine_server_call_err( req ))
2671 retval = reply->first_sibling;
2674 retval = reply->last_sibling;
2677 retval = reply->next_sibling;
2680 retval = reply->prev_sibling;
2683 retval = reply->owner;
2686 retval = reply->first_child;
2696 /***********************************************************************
2697 * WIN_InternalShowOwnedPopups
2699 * Internal version of ShowOwnedPopups; Wine functions should use this
2700 * to avoid interfering with application calls to ShowOwnedPopups
2701 * and to make sure the application can't prevent showing/hiding.
2703 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2707 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2711 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2713 if (!win_array) return TRUE;
2716 * Show windows Lowest first, Highest last to preserve Z-Order
2718 while (win_array[count]) count++;
2719 while (--count >= 0)
2721 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2722 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2724 if (pWnd->dwStyle & WS_POPUP)
2728 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2729 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2732 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2734 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2735 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2740 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2741 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2742 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2745 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2747 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2748 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2749 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2753 WIN_ReleaseWndPtr( pWnd );
2755 HeapFree( GetProcessHeap(), 0, win_array );
2760 /*******************************************************************
2761 * ShowOwnedPopups (USER32.@)
2763 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2767 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2769 if (!win_array) return TRUE;
2771 while (win_array[count]) count++;
2772 while (--count >= 0)
2774 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2775 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2777 if (pWnd->dwStyle & WS_POPUP)
2781 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2783 /* In Windows, ShowOwnedPopups(TRUE) generates
2784 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2785 * regardless of the state of the owner
2787 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2788 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2793 if (IsWindowVisible(pWnd->hwndSelf))
2795 /* In Windows, ShowOwnedPopups(FALSE) generates
2796 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2797 * regardless of the state of the owner
2799 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2800 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2804 WIN_ReleaseWndPtr( pWnd );
2806 HeapFree( GetProcessHeap(), 0, win_array );
2811 /*******************************************************************
2812 * GetLastActivePopup (USER32.@)
2814 HWND WINAPI GetLastActivePopup( HWND hwnd )
2817 WND *wndPtr =WIN_FindWndPtr(hwnd);
2818 if (!wndPtr) return hwnd;
2819 retval = wndPtr->hwndLastActive;
2820 if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2821 WIN_ReleaseWndPtr(wndPtr);
2826 /*******************************************************************
2829 * Build an array of all parents of a given window, starting with
2830 * the immediate parent. The array must be freed with HeapFree.
2831 * Returns NULL if window is a top-level window.
2833 HWND *WIN_ListParents( HWND hwnd )
2836 HWND current, *list;
2837 int pos = 0, size = 16, count = 0;
2839 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2844 if (!(win = WIN_GetPtr( current ))) goto empty;
2845 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2846 list[pos] = win->parent;
2847 WIN_ReleasePtr( win );
2848 if (!(current = list[pos]))
2850 if (!pos) goto empty;
2853 if (++pos == size - 1)
2855 /* need to grow the list */
2856 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2857 if (!new_list) goto empty;
2863 /* at least one parent belongs to another process, have to query the server */
2868 SERVER_START_REQ( get_window_parents )
2871 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2872 if (!wine_server_call( req )) count = reply->count;
2875 if (!count) goto empty;
2881 HeapFree( GetProcessHeap(), 0, list );
2883 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2887 HeapFree( GetProcessHeap(), 0, list );
2892 /*******************************************************************
2895 * Build an array of the children of a given window. The array must be
2896 * freed with HeapFree. Returns NULL when no windows are found.
2898 HWND *WIN_ListChildren( HWND hwnd )
2900 return list_window_children( hwnd, 0, 0 );
2904 /*******************************************************************
2905 * EnumWindows (USER32.@)
2907 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2913 /* We have to build a list of all windows first, to avoid */
2914 /* unpleasant side-effects, for instance if the callback */
2915 /* function changes the Z-order of the windows. */
2917 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2919 /* Now call the callback function for every window */
2921 iWndsLocks = WIN_SuspendWndsLock();
2922 for (i = 0; list[i]; i++)
2924 /* Make sure that the window still exists */
2925 if (!IsWindow( list[i] )) continue;
2926 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2928 WIN_RestoreWndsLock(iWndsLocks);
2929 HeapFree( GetProcessHeap(), 0, list );
2934 /**********************************************************************
2935 * EnumThreadWindows (USER32.@)
2937 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2942 if (!(list = list_window_children( GetDesktopWindow(), 0, GetCurrentThreadId() )))
2945 /* Now call the callback function for every window */
2947 iWndsLocks = WIN_SuspendWndsLock();
2948 for (i = 0; list[i]; i++)
2949 if (!func( list[i], lParam )) break;
2950 WIN_RestoreWndsLock(iWndsLocks);
2951 HeapFree( GetProcessHeap(), 0, list );
2956 /**********************************************************************
2957 * WIN_EnumChildWindows
2959 * Helper function for EnumChildWindows().
2961 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2966 for ( ; *list; list++)
2968 /* Make sure that the window still exists */
2969 if (!IsWindow( *list )) continue;
2970 /* skip owned windows */
2971 if (GetWindow( *list, GW_OWNER )) continue;
2972 /* Build children list first */
2973 childList = WIN_ListChildren( *list );
2975 ret = func( *list, lParam );
2979 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2980 HeapFree( GetProcessHeap(), 0, childList );
2982 if (!ret) return FALSE;
2988 /**********************************************************************
2989 * EnumChildWindows (USER32.@)
2991 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2996 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2997 iWndsLocks = WIN_SuspendWndsLock();
2998 WIN_EnumChildWindows( list, func, lParam );
2999 WIN_RestoreWndsLock(iWndsLocks);
3000 HeapFree( GetProcessHeap(), 0, list );
3005 /*******************************************************************
3006 * AnyPopup (USER.52)
3008 BOOL16 WINAPI AnyPopup16(void)
3014 /*******************************************************************
3015 * AnyPopup (USER32.@)
3017 BOOL WINAPI AnyPopup(void)
3021 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3023 if (!list) return FALSE;
3024 for (i = 0; list[i]; i++)
3026 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3028 retvalue = (list[i] != 0);
3029 HeapFree( GetProcessHeap(), 0, list );
3034 /*******************************************************************
3035 * FlashWindow (USER32.@)
3037 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3039 WND *wndPtr = WIN_FindWndPtr(hWnd);
3041 TRACE("%04x\n", hWnd);
3043 if (!wndPtr) return FALSE;
3044 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3046 if (wndPtr->dwStyle & WS_MINIMIZE)
3048 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3050 HDC hDC = GetDC(hWnd);
3052 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
3053 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3055 ReleaseDC( hWnd, hDC );
3056 wndPtr->flags |= WIN_NCACTIVATED;
3060 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3061 wndPtr->flags &= ~WIN_NCACTIVATED;
3063 WIN_ReleaseWndPtr(wndPtr);
3069 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3070 else wparam = (hWnd == GetActiveWindow());
3072 WIN_ReleaseWndPtr(wndPtr);
3073 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3079 /*******************************************************************
3080 * GetWindowContextHelpId (USER32.@)
3082 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3085 WND *wnd = WIN_FindWndPtr( hwnd );
3087 retval = wnd->helpContext;
3088 WIN_ReleaseWndPtr(wnd);
3093 /*******************************************************************
3094 * SetWindowContextHelpId (USER32.@)
3096 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3098 WND *wnd = WIN_FindWndPtr( hwnd );
3099 if (!wnd) return FALSE;
3100 wnd->helpContext = id;
3101 WIN_ReleaseWndPtr(wnd);
3106 /*******************************************************************
3109 * recursively find a child that contains spDragInfo->pt point
3110 * and send WM_QUERYDROPOBJECT
3112 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
3114 BOOL16 wParam, bResult = 0;
3116 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3119 if (!ptrDragInfo) return FALSE;
3121 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3123 GetWindowRect(hQueryWnd,&tempRect);
3125 if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
3127 if (!IsIconic( hQueryWnd ))
3129 GetClientRect( hQueryWnd, &tempRect );
3130 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
3132 if (PtInRect( &tempRect, pt))
3135 HWND *list = WIN_ListChildren( hQueryWnd );
3141 for (i = 0; list[i]; i++)
3143 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
3145 GetWindowRect( list[i], &tempRect );
3146 if (PtInRect( &tempRect, pt )) break;
3151 if (IsWindowEnabled( list[i] ))
3152 bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
3154 HeapFree( GetProcessHeap(), 0, list );
3156 if(bResult) return bResult;
3162 ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
3164 ptrDragInfo->hScope = hQueryWnd;
3166 if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
3167 else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
3169 if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3175 /*******************************************************************
3176 * DragDetect (USER32.@)
3178 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3183 rect.left = pt.x - wDragWidth;
3184 rect.right = pt.x + wDragWidth;
3186 rect.top = pt.y - wDragHeight;
3187 rect.bottom = pt.y + wDragHeight;
3193 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3195 if( msg.message == WM_LBUTTONUP )
3200 if( msg.message == WM_MOUSEMOVE )
3203 tmp.x = LOWORD(msg.lParam);
3204 tmp.y = HIWORD(msg.lParam);
3205 if( !PtInRect( &rect, tmp ))
3217 /******************************************************************************
3218 * DragObject (USER.464)
3220 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3221 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3224 LPDRAGINFO16 lpDragInfo;
3226 HCURSOR16 hOldCursor=0, hBummer=0;
3227 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3228 HCURSOR16 hCurrentCursor = 0;
3229 HWND16 hCurrentWnd = 0;
3231 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3232 spDragInfo = K32WOWGlobalLock16(hDragInfo);
3234 if( !lpDragInfo || !spDragInfo ) return 0L;
3236 if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
3238 GlobalFree16(hDragInfo);
3242 if(hCursor) hOldCursor = SetCursor(hCursor);
3244 lpDragInfo->hWnd = hWnd;
3245 lpDragInfo->hScope = 0;
3246 lpDragInfo->wFlags = wObj;
3247 lpDragInfo->hList = szList; /* near pointer! */
3248 lpDragInfo->hOfStruct = hOfStruct;
3256 GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
3258 *(lpDragInfo+1) = *lpDragInfo;
3260 lpDragInfo->pt.x = msg.pt.x;
3261 lpDragInfo->pt.y = msg.pt.y;
3263 /* update DRAGINFO struct */
3264 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3266 if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
3267 hCurrentCursor = hCursor;
3270 hCurrentCursor = hBummer;
3271 lpDragInfo->hScope = 0;
3273 if( hCurrentCursor )
3274 SetCursor(hCurrentCursor);
3276 /* send WM_DRAGLOOP */
3277 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3278 (LPARAM) spDragInfo );
3279 /* send WM_DRAGSELECT or WM_DRAGMOVE */
3280 if( hCurrentWnd != lpDragInfo->hScope )
3283 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3284 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3285 HIWORD(spDragInfo)) );
3286 hCurrentWnd = lpDragInfo->hScope;
3288 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3292 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3294 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3297 ShowCursor( FALSE );
3299 if( hCursor ) SetCursor( hOldCursor );
3301 if( hCurrentCursor != hBummer )
3302 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3303 (WPARAM16)hWnd, (LPARAM)spDragInfo );
3306 GlobalFree16(hDragInfo);
3308 return (DWORD)(msg.lParam);
3312 /******************************************************************************
3313 * GetWindowModuleFileNameA (USER32.@)
3315 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3317 FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3318 hwnd, lpszFileName, cchFileNameMax);
3322 /******************************************************************************
3323 * GetWindowModuleFileNameW (USER32.@)
3325 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3327 FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3328 hwnd, lpszFileName, cchFileNameMax);
3332 /******************************************************************************
3333 * GetWindowInfo (USER32.@)
3336 * MS Documentation mentions that pwi->cbSize must be set to SIZEOF(WINDOWINFO)
3337 * this may be because this structure changed over time. If this is the
3338 * the case, then please: FIXME.
3339 * Using the structure described in MSDN for 98/ME/NT(4.0 SP3)/2000/XP.
3341 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3343 WND *wndInfo = NULL;
3344 if (!pwi) return FALSE;
3345 if (pwi->cbSize != sizeof(WINDOWINFO))
3347 FIXME("windowinfo->cbSize != sizeof(WINDOWINFO). Please report\n");
3350 wndInfo = WIN_GetPtr(hwnd);
3351 if (!wndInfo) return FALSE;
3352 if (wndInfo == WND_OTHER_PROCESS)
3354 FIXME("window belong to other process\n");
3358 pwi->rcWindow = wndInfo->rectWindow;
3359 pwi->rcClient = wndInfo->rectClient;
3360 pwi->dwStyle = wndInfo->dwStyle;
3361 pwi->dwExStyle = wndInfo->dwExStyle;
3362 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3363 /* if active WS_ACTIVECAPTION, else 0 */
3365 pwi->cxWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3366 GetSystemMetrics(SM_CXBORDER) : 0);
3367 pwi->cyWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3368 GetSystemMetrics(SM_CYBORDER) : 0);
3369 /* above two: I'm presuming that borders widths are the same
3370 * for each window - so long as its actually using a border.. */
3372 pwi->atomWindowType = GetClassLongA( hwnd, GCW_ATOM );
3373 pwi->wCreatorVersion = GetVersion();
3374 /* Docs say this should be the version that
3375 * CREATED the window. But eh?.. Isn't that just the
3376 * version we are running.. Unless ofcourse its some wacky
3377 * RPC stuff or something */
3379 WIN_ReleasePtr(wndInfo);