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 )) return FALSE;
799 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
800 WIN_ReleaseWndPtr( pWndDesktop );
805 /***********************************************************************
808 * Fix the coordinates - Helper for WIN_CreateWindowEx.
809 * returns default show mode in sw.
810 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
812 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
814 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
815 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
817 if (cs->style & (WS_CHILD | WS_POPUP))
819 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
820 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
822 else /* overlapped window */
826 GetStartupInfoA( &info );
828 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
830 /* Never believe Microsoft's documentation... CreateWindowEx doc says
831 * that if an overlapped window is created with WS_VISIBLE style bit
832 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
833 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
836 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
837 * 2) it does not ignore the y parameter as the docs claim; instead, it
838 * uses it as second parameter to ShowWindow() unless y is either
839 * CW_USEDEFAULT or CW_USEDEFAULT16.
841 * The fact that we didn't do 2) caused bogus windows pop up when wine
842 * was running apps that were using this obscure feature. Example -
843 * calc.exe that comes with Win98 (only Win98, it's different from
844 * the one that comes with Win95 and NT)
846 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
847 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
848 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
851 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
853 if (info.dwFlags & STARTF_USESIZE)
855 cs->cx = info.dwXSize;
856 cs->cy = info.dwYSize;
858 else /* if no other hint from the app, pick 3/4 of the screen real estate */
861 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
862 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
863 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
870 /* neither x nor cx are default. Check the y values .
871 * In the trace we see Outlook and Outlook Express using
872 * cy set to CW_USEDEFAULT when opening the address book.
874 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
876 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
877 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
878 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
883 /***********************************************************************
886 static void dump_window_styles( DWORD style, DWORD exstyle )
889 if(style & WS_POPUP) DPRINTF(" WS_POPUP");
890 if(style & WS_CHILD) DPRINTF(" WS_CHILD");
891 if(style & WS_MINIMIZE) DPRINTF(" WS_MINIMIZE");
892 if(style & WS_VISIBLE) DPRINTF(" WS_VISIBLE");
893 if(style & WS_DISABLED) DPRINTF(" WS_DISABLED");
894 if(style & WS_CLIPSIBLINGS) DPRINTF(" WS_CLIPSIBLINGS");
895 if(style & WS_CLIPCHILDREN) DPRINTF(" WS_CLIPCHILDREN");
896 if(style & WS_MAXIMIZE) DPRINTF(" WS_MAXIMIZE");
897 if((style & WS_CAPTION) == WS_CAPTION) DPRINTF(" WS_CAPTION");
900 if(style & WS_BORDER) DPRINTF(" WS_BORDER");
901 if(style & WS_DLGFRAME) DPRINTF(" WS_DLGFRAME");
903 if(style & WS_VSCROLL) DPRINTF(" WS_VSCROLL");
904 if(style & WS_HSCROLL) DPRINTF(" WS_HSCROLL");
905 if(style & WS_SYSMENU) DPRINTF(" WS_SYSMENU");
906 if(style & WS_THICKFRAME) DPRINTF(" WS_THICKFRAME");
907 if(style & WS_GROUP) DPRINTF(" WS_GROUP");
908 if(style & WS_TABSTOP) DPRINTF(" WS_TABSTOP");
909 if(style & WS_MINIMIZEBOX) DPRINTF(" WS_MINIMIZEBOX");
910 if(style & WS_MAXIMIZEBOX) DPRINTF(" WS_MAXIMIZEBOX");
912 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
913 #define DUMPED_STYLES \
933 if(style & ~DUMPED_STYLES) DPRINTF(" %08lx", style & ~DUMPED_STYLES);
938 if(exstyle & WS_EX_DLGMODALFRAME) DPRINTF(" WS_EX_DLGMODALFRAME");
939 if(exstyle & WS_EX_DRAGDETECT) DPRINTF(" WS_EX_DRAGDETECT");
940 if(exstyle & WS_EX_NOPARENTNOTIFY) DPRINTF(" WS_EX_NOPARENTNOTIFY");
941 if(exstyle & WS_EX_TOPMOST) DPRINTF(" WS_EX_TOPMOST");
942 if(exstyle & WS_EX_ACCEPTFILES) DPRINTF(" WS_EX_ACCEPTFILES");
943 if(exstyle & WS_EX_TRANSPARENT) DPRINTF(" WS_EX_TRANSPARENT");
944 if(exstyle & WS_EX_MDICHILD) DPRINTF(" WS_EX_MDICHILD");
945 if(exstyle & WS_EX_TOOLWINDOW) DPRINTF(" WS_EX_TOOLWINDOW");
946 if(exstyle & WS_EX_WINDOWEDGE) DPRINTF(" WS_EX_WINDOWEDGE");
947 if(exstyle & WS_EX_CLIENTEDGE) DPRINTF(" WS_EX_CLIENTEDGE");
948 if(exstyle & WS_EX_CONTEXTHELP) DPRINTF(" WS_EX_CONTEXTHELP");
949 if(exstyle & WS_EX_RIGHT) DPRINTF(" WS_EX_RIGHT");
950 if(exstyle & WS_EX_RTLREADING) DPRINTF(" WS_EX_RTLREADING");
951 if(exstyle & WS_EX_LEFTSCROLLBAR) DPRINTF(" WS_EX_LEFTSCROLLBAR");
952 if(exstyle & WS_EX_CONTROLPARENT) DPRINTF(" WS_EX_CONTROLPARENT");
953 if(exstyle & WS_EX_STATICEDGE) DPRINTF(" WS_EX_STATICEDGE");
954 if(exstyle & WS_EX_APPWINDOW) DPRINTF(" WS_EX_APPWINDOW");
955 if(exstyle & WS_EX_LAYERED) DPRINTF(" WS_EX_LAYERED");
957 #define DUMPED_EX_STYLES \
958 (WS_EX_DLGMODALFRAME | \
960 WS_EX_NOPARENTNOTIFY | \
962 WS_EX_ACCEPTFILES | \
963 WS_EX_TRANSPARENT | \
968 WS_EX_CONTEXTHELP | \
971 WS_EX_LEFTSCROLLBAR | \
972 WS_EX_CONTROLPARENT | \
977 if(exstyle & ~DUMPED_EX_STYLES) DPRINTF(" %08lx", exstyle & ~DUMPED_EX_STYLES);
979 #undef DUMPED_EX_STYLES
983 /***********************************************************************
986 * Implementation of CreateWindowEx().
988 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
989 WINDOWPROCTYPE type )
992 struct tagCLASS *classPtr;
994 HWND hwnd, parent, owner;
999 BOOL unicode = (type == WIN_PROC_32W);
1001 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%04x menu=%04x inst=%08x params=%p\n",
1002 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszName) : debugres_a(cs->lpszName),
1003 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszClass) : debugres_a(cs->lpszClass),
1004 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1005 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1007 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1009 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1010 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1012 /* Find the parent window */
1014 parent = GetDesktopWindow();
1018 /* Make sure parent is valid */
1019 if (!IsWindow( cs->hwndParent ))
1021 WARN("Bad parent %04x\n", cs->hwndParent );
1024 if (cs->style & WS_CHILD) parent = WIN_GetFullHandle(cs->hwndParent);
1025 else owner = GetAncestor( cs->hwndParent, GA_ROOT );
1027 else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP))
1029 WARN("No parent for child window\n" );
1030 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1033 /* Find the window class */
1034 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
1035 &wndExtra, &winproc, &clsStyle, &dce )))
1037 WARN("Bad class '%s'\n", cs->lpszClass );
1041 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1043 /* Correct the window style - stage 1
1045 * These are patches that appear to affect both the style loaded into the
1046 * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
1048 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1049 * why does the user get to set it?
1052 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1053 * tested for WS_POPUP
1055 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1056 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1057 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1058 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1060 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1062 /* Create the window structure */
1064 if (!(wndPtr = create_window_handle( parent, owner, classAtom,
1065 sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
1067 TRACE("out of memory\n" );
1070 hwnd = wndPtr->hwndSelf;
1072 /* Fill the window structure */
1074 wndPtr->tid = GetCurrentThreadId();
1075 wndPtr->owner = owner;
1076 wndPtr->parent = parent;
1077 wndPtr->class = classPtr;
1078 wndPtr->winproc = winproc;
1079 wndPtr->hInstance = cs->hInstance;
1080 wndPtr->text = NULL;
1081 wndPtr->hmemTaskQ = InitThreadInput16( 0, 0 );
1082 wndPtr->hrgnUpdate = 0;
1083 wndPtr->hrgnWnd = 0;
1084 wndPtr->hwndLastActive = hwnd;
1085 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1086 wndPtr->dwExStyle = cs->dwExStyle;
1087 wndPtr->clsStyle = clsStyle;
1088 wndPtr->wIDmenu = 0;
1089 wndPtr->helpContext = 0;
1090 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1091 wndPtr->pVScroll = NULL;
1092 wndPtr->pHScroll = NULL;
1093 wndPtr->userdata = 0;
1094 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU)
1095 ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1096 wndPtr->cbWndExtra = wndExtra;
1098 if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
1100 /* Correct the window style - stage 2 */
1102 if (!(cs->style & WS_CHILD))
1104 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1105 if (!(cs->style & WS_POPUP))
1107 wndPtr->dwStyle |= WS_CAPTION;
1108 wndPtr->flags |= WIN_NEED_SIZE;
1111 SERVER_START_REQ( set_window_info )
1114 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1115 req->style = wndPtr->dwStyle;
1116 req->ex_style = wndPtr->dwExStyle;
1117 req->instance = (void *)wndPtr->hInstance;
1118 wine_server_call( req );
1122 /* Get class or window DC if needed */
1124 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1125 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
1126 else wndPtr->dce = NULL;
1128 /* Set the window menu */
1130 if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
1132 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1135 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1138 if (HIWORD(cs->hInstance))
1139 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1141 cs->hMenu = LoadMenu16(cs->hInstance,menuName);
1143 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1147 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1148 WIN_ReleaseWndPtr( wndPtr );
1150 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1152 WIN_DestroyWindow( hwnd );
1156 /* Notify the parent window only */
1158 send_parent_notify( hwnd, WM_CREATE );
1159 if (!IsWindow( hwnd )) return 0;
1161 if (cs->style & WS_VISIBLE)
1163 /* in case WS_VISIBLE got set in the meantime */
1164 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1165 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1166 WIN_ReleasePtr( wndPtr );
1167 ShowWindow( hwnd, sw );
1170 /* Call WH_SHELL hook */
1172 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1173 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
1175 TRACE("created window %04x\n", hwnd);
1180 /***********************************************************************
1181 * CreateWindow (USER.41)
1183 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1184 DWORD style, INT16 x, INT16 y, INT16 width,
1185 INT16 height, HWND16 parent, HMENU16 menu,
1186 HINSTANCE16 instance, LPVOID data )
1188 return CreateWindowEx16( 0, className, windowName, style,
1189 x, y, width, height, parent, menu, instance, data );
1193 /***********************************************************************
1194 * CreateWindowEx (USER.452)
1196 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1197 LPCSTR windowName, DWORD style, INT16 x,
1198 INT16 y, INT16 width, INT16 height,
1199 HWND16 parent, HMENU16 menu,
1200 HINSTANCE16 instance, LPVOID data )
1206 /* Find the class atom */
1208 if (HIWORD(className))
1210 if (!(classAtom = GlobalFindAtomA( className )))
1212 ERR( "bad class name %s\n", debugres_a(className) );
1218 classAtom = LOWORD(className);
1219 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1221 ERR( "bad atom %x\n", classAtom);
1227 /* Fix the coordinates */
1229 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1230 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1231 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1232 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1234 /* Create the window */
1236 cs.lpCreateParams = data;
1237 cs.hInstance = (HINSTANCE)instance;
1238 cs.hMenu = (HMENU)menu;
1239 cs.hwndParent = WIN_Handle32( parent );
1241 cs.lpszName = windowName;
1242 cs.lpszClass = className;
1243 cs.dwExStyle = exStyle;
1245 return WIN_Handle16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1249 /***********************************************************************
1250 * CreateWindowExA (USER32.@)
1252 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1253 LPCSTR windowName, DWORD style, INT x,
1254 INT y, INT width, INT height,
1255 HWND parent, HMENU menu,
1256 HINSTANCE instance, LPVOID data )
1263 instance=GetModuleHandleA(NULL);
1265 if(exStyle & WS_EX_MDICHILD)
1266 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1268 /* Find the class atom */
1270 if (HIWORD(className))
1272 if (!(classAtom = GlobalFindAtomA( className )))
1274 ERR( "bad class name %s\n", debugres_a(className) );
1280 classAtom = LOWORD(className);
1281 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1283 ERR( "bad atom %x\n", classAtom);
1289 /* Create the window */
1291 cs.lpCreateParams = data;
1292 cs.hInstance = instance;
1294 cs.hwndParent = parent;
1300 cs.lpszName = windowName;
1301 cs.lpszClass = className;
1302 cs.dwExStyle = exStyle;
1304 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1308 /***********************************************************************
1309 * CreateWindowExW (USER32.@)
1311 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1312 LPCWSTR windowName, DWORD style, INT x,
1313 INT y, INT width, INT height,
1314 HWND parent, HMENU menu,
1315 HINSTANCE instance, LPVOID data )
1322 instance=GetModuleHandleA(NULL);
1324 if(exStyle & WS_EX_MDICHILD)
1325 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1327 /* Find the class atom */
1329 if (HIWORD(className))
1331 if (!(classAtom = GlobalFindAtomW( className )))
1333 ERR( "bad class name %s\n", debugres_w(className) );
1339 classAtom = LOWORD(className);
1340 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1342 ERR( "bad atom %x\n", classAtom);
1348 /* Create the window */
1350 cs.lpCreateParams = data;
1351 cs.hInstance = instance;
1353 cs.hwndParent = parent;
1359 cs.lpszName = windowName;
1360 cs.lpszClass = className;
1361 cs.dwExStyle = exStyle;
1363 /* Note: we rely on the fact that CREATESTRUCTA and */
1364 /* CREATESTRUCTW have the same layout. */
1365 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1369 /***********************************************************************
1370 * WIN_SendDestroyMsg
1372 static void WIN_SendDestroyMsg( HWND hwnd )
1374 if( CARET_GetHwnd() == hwnd) DestroyCaret();
1375 if (USER_Driver.pResetSelectionOwner)
1376 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1379 * Send the WM_DESTROY to the window.
1381 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1384 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1385 * make sure that the window still exists when we come back.
1392 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1394 /* start from the end (FIXME: is this needed?) */
1395 for (i = 0; pWndArray[i]; i++) ;
1399 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1401 HeapFree( GetProcessHeap(), 0, pWndArray );
1404 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1408 /***********************************************************************
1409 * DestroyWindow (USER32.@)
1411 BOOL WINAPI DestroyWindow( HWND hwnd )
1416 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1418 SetLastError( ERROR_ACCESS_DENIED );
1422 TRACE("(%04x)\n", hwnd);
1424 /* Look whether the focus is within the tree of windows we will
1428 if (h == hwnd || IsChild( hwnd, h ))
1430 HWND parent = GetAncestor( hwnd, GA_PARENT );
1431 if (parent == GetDesktopWindow()) parent = 0;
1437 if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
1439 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1443 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1444 send_parent_notify( hwnd, WM_DESTROY );
1446 else if (!GetWindow( hwnd, GW_OWNER ))
1448 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
1449 /* FIXME: clean up palette - see "Internals" p.352 */
1452 if (!IsWindow(hwnd)) return TRUE;
1454 if (USER_Driver.pResetSelectionOwner)
1455 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1457 /* Hide the window */
1459 ShowWindow( hwnd, SW_HIDE );
1460 if (!IsWindow(hwnd)) return TRUE;
1462 /* Recursively destroy owned windows */
1471 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1474 for (i = 0; list[i]; i++)
1476 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1477 if (WIN_IsCurrentThread( list[i] ))
1479 DestroyWindow( list[i] );
1483 WIN_SetOwner( list[i], 0 );
1485 HeapFree( GetProcessHeap(), 0, list );
1487 if (!got_one) break;
1490 WINPOS_ActivateOtherWindow( hwnd );
1492 if ((owner = GetWindow( hwnd, GW_OWNER )))
1494 WND *ptr = WIN_FindWndPtr( owner );
1497 if (ptr->hwndLastActive == hwnd) ptr->hwndLastActive = owner;
1498 WIN_ReleaseWndPtr( ptr );
1503 /* Send destroy messages */
1505 WIN_SendDestroyMsg( hwnd );
1506 if (!IsWindow( hwnd )) return TRUE;
1508 /* Unlink now so we won't bother with the children later on */
1510 WIN_UnlinkWindow( hwnd );
1512 /* Destroy the window storage */
1514 WIN_DestroyWindow( hwnd );
1519 /***********************************************************************
1520 * CloseWindow (USER32.@)
1522 BOOL WINAPI CloseWindow( HWND hwnd )
1524 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1525 ShowWindow( hwnd, SW_MINIMIZE );
1530 /***********************************************************************
1531 * OpenIcon (USER32.@)
1533 BOOL WINAPI OpenIcon( HWND hwnd )
1535 if (!IsIconic( hwnd )) return FALSE;
1536 ShowWindow( hwnd, SW_SHOWNORMAL );
1541 /***********************************************************************
1544 * Implementation of FindWindow() and FindWindowEx().
1546 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1551 WCHAR *buffer = NULL;
1553 if (!parent) parent = GetDesktopWindow();
1556 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1557 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1560 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1564 child = WIN_GetFullHandle( child );
1565 while (list[i] && list[i] != child) i++;
1566 if (!list[i]) goto done;
1567 i++; /* start from next window */
1574 if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1581 if (list) HeapFree( GetProcessHeap(), 0, list );
1582 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1588 /***********************************************************************
1589 * FindWindowA (USER32.@)
1591 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1593 HWND ret = FindWindowExA( 0, 0, className, title );
1594 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1599 /***********************************************************************
1600 * FindWindowExA (USER32.@)
1602 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1603 LPCSTR className, LPCSTR title )
1612 /* If the atom doesn't exist, then no class */
1613 /* with this name exists either. */
1614 if (!(atom = GlobalFindAtomA( className )))
1616 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1620 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1622 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1623 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1624 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1625 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1626 HeapFree( GetProcessHeap(), 0, buffer );
1631 /***********************************************************************
1632 * FindWindowExW (USER32.@)
1634 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1635 LPCWSTR className, LPCWSTR title )
1641 /* If the atom doesn't exist, then no class */
1642 /* with this name exists either. */
1643 if (!(atom = GlobalFindAtomW( className )))
1645 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1649 return WIN_FindWindow( parent, child, atom, title );
1653 /***********************************************************************
1654 * FindWindowW (USER32.@)
1656 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1658 return FindWindowExW( 0, 0, className, title );
1662 /**********************************************************************
1663 * GetDesktopWindow (USER32.@)
1665 HWND WINAPI GetDesktopWindow(void)
1667 if (pWndDesktop) return pWndDesktop->hwndSelf;
1668 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" );
1674 /*******************************************************************
1675 * EnableWindow (USER32.@)
1677 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1684 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1685 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1689 TRACE("( %x, %d )\n", hwnd, enable);
1691 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1692 style = wndPtr->dwStyle;
1693 retvalue = ((style & WS_DISABLED) != 0);
1694 WIN_ReleasePtr( wndPtr );
1696 if (enable && retvalue)
1698 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1699 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1701 else if (!enable && !retvalue)
1703 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1705 WIN_SetStyle( hwnd, style | WS_DISABLED );
1707 if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
1708 SetFocus( 0 ); /* A disabled window can't have the focus */
1710 if (hwnd == GetCapture() || IsChild(hwnd, GetCapture()))
1711 ReleaseCapture(); /* A disabled window can't capture the mouse */
1713 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1719 /***********************************************************************
1720 * IsWindowEnabled (USER32.@)
1722 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1724 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1728 /***********************************************************************
1729 * IsWindowUnicode (USER32.@)
1731 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1736 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1737 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1738 WIN_ReleaseWndPtr(wndPtr);
1743 /**********************************************************************
1744 * GetWindowWord (USER32.@)
1746 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1751 WND *wndPtr = WIN_GetPtr( hwnd );
1754 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1757 if (wndPtr == WND_OTHER_PROCESS)
1759 if (IsWindow( hwnd ))
1760 FIXME( "(%d) not supported yet on other process window %x\n", offset, hwnd );
1761 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1764 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1766 WARN("Invalid offset %d\n", offset );
1767 SetLastError( ERROR_INVALID_INDEX );
1769 else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1770 WIN_ReleasePtr( wndPtr );
1776 case GWL_HWNDPARENT:
1777 return GetWindowLongW( hwnd, offset );
1781 LONG ret = GetWindowLongW( hwnd, offset );
1783 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1787 WARN("Invalid offset %d\n", offset );
1793 /**********************************************************************
1794 * SetWindowWord (USER32.@)
1796 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1805 case GWL_HWNDPARENT:
1806 return SetWindowLongW( hwnd, offset, (UINT)newval );
1810 WARN("Invalid offset %d\n", offset );
1811 SetLastError( ERROR_INVALID_INDEX );
1816 wndPtr = WIN_GetPtr( hwnd );
1817 if (wndPtr == WND_OTHER_PROCESS)
1820 FIXME( "set %d <- %x not supported yet on other process window %x\n",
1821 offset, newval, hwnd );
1826 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1830 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1832 WARN("Invalid offset %d\n", offset );
1833 WIN_ReleasePtr(wndPtr);
1834 SetLastError( ERROR_INVALID_INDEX );
1837 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1840 WIN_ReleasePtr(wndPtr);
1845 /**********************************************************************
1848 * Helper function for GetWindowLong().
1850 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1855 if (offset == GWL_HWNDPARENT) return (LONG)GetParent( hwnd );
1857 if (!(wndPtr = WIN_GetPtr( hwnd )))
1859 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1863 if (wndPtr == WND_OTHER_PROCESS)
1868 FIXME( "(%d) not supported on other process window %x\n", offset, hwnd );
1869 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1872 if (offset == GWL_WNDPROC)
1874 SetLastError( ERROR_ACCESS_DENIED );
1877 SERVER_START_REQ( set_window_info )
1880 req->flags = 0; /* don't set anything, just retrieve */
1881 if (!wine_server_call_err( req ))
1885 case GWL_STYLE: retvalue = reply->old_style; break;
1886 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1887 case GWL_ID: retvalue = reply->old_id; break;
1888 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1889 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1891 SetLastError( ERROR_INVALID_INDEX );
1900 /* now we have a valid wndPtr */
1904 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1907 * Some programs try to access last element from 16 bit
1908 * code using illegal offset value. Hopefully this is
1909 * what those programs really expect.
1911 if (type == WIN_PROC_16 &&
1912 wndPtr->cbWndExtra >= 4 &&
1913 offset == wndPtr->cbWndExtra - sizeof(WORD))
1915 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1917 ERR( "- replaced invalid offset %d with %d\n",
1920 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1921 WIN_ReleasePtr( wndPtr );
1924 WARN("Invalid offset %d\n", offset );
1925 WIN_ReleasePtr( wndPtr );
1926 SetLastError( ERROR_INVALID_INDEX );
1929 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1930 /* Special case for dialog window procedure */
1931 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1932 retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1933 WIN_ReleasePtr( wndPtr );
1939 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
1940 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1941 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1942 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
1943 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1944 case GWL_HINSTANCE: retvalue = wndPtr->hInstance; break;
1946 WARN("Unknown offset %d\n", offset );
1947 SetLastError( ERROR_INVALID_INDEX );
1950 WIN_ReleasePtr(wndPtr);
1955 /**********************************************************************
1958 * Helper function for SetWindowLong().
1960 * 0 is the failure code. However, in the case of failure SetLastError
1961 * must be set to distinguish between a 0 return value and a failure.
1963 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1964 WINDOWPROCTYPE type )
1969 TRACE( "%x %d %lx %x\n", hwnd, offset, newval, type );
1971 if (!WIN_IsCurrentProcess( hwnd ))
1973 if (offset == GWL_WNDPROC)
1975 SetLastError( ERROR_ACCESS_DENIED );
1978 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1981 wndPtr = WIN_GetPtr( hwnd );
1985 LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1986 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1988 WARN("Invalid offset %d\n", offset );
1989 WIN_ReleasePtr( wndPtr );
1990 SetLastError( ERROR_INVALID_INDEX );
1993 /* Special case for dialog window procedure */
1994 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1996 retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1997 WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
1998 type, WIN_PROC_WINDOW );
1999 WIN_ReleasePtr( wndPtr );
2004 WIN_ReleasePtr( wndPtr );
2011 /* first some special cases */
2016 style.styleOld = wndPtr->dwStyle;
2017 style.styleNew = newval;
2018 WIN_ReleasePtr( wndPtr );
2019 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2020 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2021 newval = style.styleNew;
2023 case GWL_HWNDPARENT:
2024 WIN_ReleasePtr( wndPtr );
2025 return (LONG)SetParent( hwnd, (HWND)newval );
2027 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2028 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
2029 type, WIN_PROC_WINDOW );
2030 WIN_ReleasePtr( wndPtr );
2037 WIN_ReleasePtr( wndPtr );
2038 WARN("Invalid offset %d\n", offset );
2039 SetLastError( ERROR_INVALID_INDEX );
2043 SERVER_START_REQ( set_window_info )
2049 req->flags = SET_WIN_STYLE;
2050 req->style = newval;
2053 req->flags = SET_WIN_EXSTYLE;
2054 req->ex_style = newval;
2057 req->flags = SET_WIN_ID;
2061 req->flags = SET_WIN_INSTANCE;
2062 req->instance = (void *)newval;
2065 req->flags = SET_WIN_USERDATA;
2066 req->user_data = (void *)newval;
2069 if ((ok = !wine_server_call_err( req )))
2074 wndPtr->dwStyle = newval;
2075 retval = reply->old_style;
2078 wndPtr->dwExStyle = newval;
2079 retval = reply->old_ex_style;
2082 wndPtr->wIDmenu = newval;
2083 retval = reply->old_id;
2086 wndPtr->hInstance = newval;
2087 retval = (HINSTANCE)reply->old_instance;
2090 wndPtr->userdata = newval;
2091 retval = (ULONG_PTR)reply->old_user_data;
2097 WIN_ReleasePtr( wndPtr );
2101 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2102 USER_Driver.pSetWindowStyle( hwnd, retval );
2104 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2105 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2112 /**********************************************************************
2113 * GetWindowLong (USER.135)
2115 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2117 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2121 /**********************************************************************
2122 * GetWindowLongA (USER32.@)
2124 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2126 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2130 /**********************************************************************
2131 * GetWindowLongW (USER32.@)
2133 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2135 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2139 /**********************************************************************
2140 * SetWindowLong (USER.136)
2142 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2144 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2148 /**********************************************************************
2149 * SetWindowLongA (USER32.@)
2151 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2153 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2157 /**********************************************************************
2158 * SetWindowLongW (USER32.@) Set window attribute
2160 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2161 * value in a window's extra memory.
2163 * The _hwnd_ parameter specifies the window. is the handle to a
2164 * window that has extra memory. The _newval_ parameter contains the
2165 * new attribute or extra memory value. If positive, the _offset_
2166 * parameter is the byte-addressed location in the window's extra
2167 * memory to set. If negative, _offset_ specifies the window
2168 * attribute to set, and should be one of the following values:
2170 * GWL_EXSTYLE The window's extended window style
2172 * GWL_STYLE The window's window style.
2174 * GWL_WNDPROC Pointer to the window's window procedure.
2176 * GWL_HINSTANCE The window's pplication instance handle.
2178 * GWL_ID The window's identifier.
2180 * GWL_USERDATA The window's user-specified data.
2182 * If the window is a dialog box, the _offset_ parameter can be one of
2183 * the following values:
2185 * DWL_DLGPROC The address of the window's dialog box procedure.
2187 * DWL_MSGRESULT The return value of a message
2188 * that the dialog box procedure processed.
2190 * DWL_USER Application specific information.
2194 * If successful, returns the previous value located at _offset_. Otherwise,
2199 * Extra memory for a window class is specified by a nonzero cbWndExtra
2200 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2201 * time of class creation.
2203 * Using GWL_WNDPROC to set a new window procedure effectively creates
2204 * a window subclass. Use CallWindowProc() in the new windows procedure
2205 * to pass messages to the superclass's window procedure.
2207 * The user data is reserved for use by the application which created
2210 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2211 * instead, call the EnableWindow() function to change the window's
2214 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2215 * SetParent() instead.
2218 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2219 * it sends WM_STYLECHANGING before changing the settings
2220 * and WM_STYLECHANGED afterwards.
2221 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2223 LONG WINAPI SetWindowLongW(
2224 HWND hwnd, /* [in] window to alter */
2225 INT offset, /* [in] offset, in bytes, of location to alter */
2226 LONG newval /* [in] new value of location */
2228 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2232 /*******************************************************************
2233 * GetWindowTextA (USER32.@)
2235 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2239 if (WIN_IsCurrentProcess( hwnd ))
2240 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2242 /* when window belongs to other process, don't send a message */
2243 if (nMaxCount <= 0) return 0;
2244 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2245 get_server_window_text( hwnd, buffer, nMaxCount );
2246 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2247 lpString[nMaxCount-1] = 0;
2248 HeapFree( GetProcessHeap(), 0, buffer );
2249 return strlen(lpString);
2253 /*******************************************************************
2254 * InternalGetWindowText (USER32.@)
2256 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2260 if (nMaxCount <= 0) return 0;
2261 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2262 if (win != WND_OTHER_PROCESS)
2264 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2265 else lpString[0] = 0;
2266 WIN_ReleasePtr( win );
2270 get_server_window_text( hwnd, lpString, nMaxCount );
2272 return strlenW(lpString);
2276 /*******************************************************************
2277 * GetWindowTextW (USER32.@)
2279 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2281 if (WIN_IsCurrentProcess( hwnd ))
2282 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2284 /* when window belongs to other process, don't send a message */
2285 if (nMaxCount <= 0) return 0;
2286 get_server_window_text( hwnd, lpString, nMaxCount );
2287 return strlenW(lpString);
2291 /*******************************************************************
2292 * SetWindowText (USER32.@)
2293 * SetWindowTextA (USER32.@)
2295 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2297 if (!WIN_IsCurrentProcess( hwnd ))
2299 FIXME( "cannot set text %s of other process window %x\n", debugstr_a(lpString), hwnd );
2300 SetLastError( ERROR_ACCESS_DENIED );
2303 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2307 /*******************************************************************
2308 * SetWindowTextW (USER32.@)
2310 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2312 if (!WIN_IsCurrentProcess( hwnd ))
2314 FIXME( "cannot set text %s of other process window %x\n", debugstr_w(lpString), hwnd );
2315 SetLastError( ERROR_ACCESS_DENIED );
2318 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2322 /*******************************************************************
2323 * GetWindowTextLengthA (USER32.@)
2325 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2327 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2330 /*******************************************************************
2331 * GetWindowTextLengthW (USER32.@)
2333 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2335 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2339 /*******************************************************************
2340 * IsWindow (USER32.@)
2342 BOOL WINAPI IsWindow( HWND hwnd )
2347 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2349 if (ptr != WND_OTHER_PROCESS)
2351 WIN_ReleasePtr( ptr );
2355 /* check other processes */
2356 SERVER_START_REQ( get_window_info )
2359 ret = !wine_server_call_err( req );
2366 /***********************************************************************
2367 * GetWindowThreadProcessId (USER32.@)
2369 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2374 if (!(ptr = WIN_GetPtr( hwnd )))
2376 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2380 if (ptr != WND_OTHER_PROCESS)
2382 /* got a valid window */
2384 if (process) *process = GetCurrentProcessId();
2385 WIN_ReleasePtr( ptr );
2389 /* check other processes */
2390 SERVER_START_REQ( get_window_info )
2393 if (!wine_server_call_err( req ))
2395 tid = (DWORD)reply->tid;
2396 if (process) *process = (DWORD)reply->pid;
2404 /*****************************************************************
2405 * GetParent (USER32.@)
2407 HWND WINAPI GetParent( HWND hwnd )
2412 if (!(wndPtr = WIN_GetPtr( hwnd )))
2414 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2417 if (wndPtr == WND_OTHER_PROCESS)
2419 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2420 if (style & (WS_POPUP | WS_CHILD))
2422 SERVER_START_REQ( get_window_tree )
2425 if (!wine_server_call_err( req ))
2427 if (style & WS_CHILD) retvalue = reply->parent;
2428 else retvalue = reply->owner;
2436 if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2437 else if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2438 WIN_ReleasePtr( wndPtr );
2444 /*****************************************************************
2445 * GetAncestor (USER32.@)
2447 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2450 HWND *list, ret = 0;
2452 if (type == GA_PARENT)
2454 if (!(win = WIN_GetPtr( hwnd )))
2456 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2459 if (win != WND_OTHER_PROCESS)
2462 WIN_ReleasePtr( win );
2464 else /* need to query the server */
2466 SERVER_START_REQ( get_window_tree )
2469 if (!wine_server_call_err( req )) ret = reply->parent;
2476 if (!(list = WIN_ListParents( hwnd ))) return 0;
2478 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2482 while (list[count]) count++;
2483 ret = list[count - 2]; /* get the one before the desktop */
2485 HeapFree( GetProcessHeap(), 0, list );
2487 if (ret && type == GA_ROOTOWNER)
2491 HWND owner = GetWindow( ret, GW_OWNER );
2500 /*****************************************************************
2501 * SetParent (USER32.@)
2503 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2506 HWND retvalue, full_handle;
2509 if (!parent) parent = GetDesktopWindow();
2510 else parent = WIN_GetFullHandle( parent );
2512 if (!IsWindow( parent ))
2514 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2518 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2519 return SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2523 if (USER_Driver.pSetParent)
2524 return USER_Driver.pSetParent( hwnd, parent );
2526 /* Windows hides the window first, then shows it again
2527 * including the WM_SHOWWINDOW messages and all */
2528 was_visible = ShowWindow( hwnd, SW_HIDE );
2530 if (!IsWindow( parent )) return 0;
2531 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2533 retvalue = wndPtr->parent; /* old parent */
2534 if (parent != retvalue)
2536 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2538 if (parent != GetDesktopWindow()) /* a child window */
2540 if (!(wndPtr->dwStyle & WS_CHILD))
2542 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2543 if (menu) DestroyMenu( menu );
2547 WIN_ReleasePtr( wndPtr );
2549 /* SetParent additionally needs to make hwnd the topmost window
2550 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2551 WM_WINDOWPOSCHANGED notification messages.
2553 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2554 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2555 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2556 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2561 /*******************************************************************
2562 * IsChild (USER32.@)
2564 BOOL WINAPI IsChild( HWND parent, HWND child )
2566 HWND *list = WIN_ListParents( child );
2570 if (!list) return FALSE;
2571 parent = WIN_GetFullHandle( parent );
2572 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2573 ret = (list[i] != 0);
2574 HeapFree( GetProcessHeap(), 0, list );
2579 /***********************************************************************
2580 * IsWindowVisible (USER32.@)
2582 BOOL WINAPI IsWindowVisible( HWND hwnd )
2588 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2589 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2590 for (i = 0; list[i]; i++)
2591 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2593 HeapFree( GetProcessHeap(), 0, list );
2598 /***********************************************************************
2599 * WIN_IsWindowDrawable
2601 * hwnd is drawable when it is visible, all parents are not
2602 * minimized, and it is itself not minimized unless we are
2603 * trying to draw its default class icon.
2605 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2610 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2612 if (!(style & WS_VISIBLE)) return FALSE;
2613 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2615 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2616 for (i = 0; list[i]; i++)
2617 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2620 HeapFree( GetProcessHeap(), 0, list );
2625 /*******************************************************************
2626 * GetTopWindow (USER32.@)
2628 HWND WINAPI GetTopWindow( HWND hwnd )
2630 if (!hwnd) hwnd = GetDesktopWindow();
2631 return GetWindow( hwnd, GW_CHILD );
2635 /*******************************************************************
2636 * GetWindow (USER32.@)
2638 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2642 if (rel == GW_OWNER) /* this one may be available locally */
2644 WND *wndPtr = WIN_GetPtr( hwnd );
2647 SetLastError( ERROR_INVALID_HANDLE );
2650 if (wndPtr != WND_OTHER_PROCESS)
2652 retval = wndPtr->owner;
2653 WIN_ReleasePtr( wndPtr );
2656 /* else fall through to server call */
2659 SERVER_START_REQ( get_window_tree )
2662 if (!wine_server_call_err( req ))
2667 retval = reply->first_sibling;
2670 retval = reply->last_sibling;
2673 retval = reply->next_sibling;
2676 retval = reply->prev_sibling;
2679 retval = reply->owner;
2682 retval = reply->first_child;
2692 /***********************************************************************
2693 * WIN_InternalShowOwnedPopups
2695 * Internal version of ShowOwnedPopups; Wine functions should use this
2696 * to avoid interfering with application calls to ShowOwnedPopups
2697 * and to make sure the application can't prevent showing/hiding.
2699 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2703 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2707 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2709 if (!win_array) return TRUE;
2712 * Show windows Lowest first, Highest last to preserve Z-Order
2714 while (win_array[count]) count++;
2715 while (--count >= 0)
2717 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2718 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2720 if (pWnd->dwStyle & WS_POPUP)
2724 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2725 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2728 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2730 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2731 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2736 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2737 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2738 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2741 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2743 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2744 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2745 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2749 WIN_ReleaseWndPtr( pWnd );
2751 HeapFree( GetProcessHeap(), 0, win_array );
2756 /*******************************************************************
2757 * ShowOwnedPopups (USER32.@)
2759 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2763 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2765 if (!win_array) return TRUE;
2767 while (win_array[count]) count++;
2768 while (--count >= 0)
2770 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2771 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2773 if (pWnd->dwStyle & WS_POPUP)
2777 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2779 /* In Windows, ShowOwnedPopups(TRUE) generates
2780 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2781 * regardless of the state of the owner
2783 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2784 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2789 if (IsWindowVisible(pWnd->hwndSelf))
2791 /* In Windows, ShowOwnedPopups(FALSE) generates
2792 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2793 * regardless of the state of the owner
2795 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2796 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2800 WIN_ReleaseWndPtr( pWnd );
2802 HeapFree( GetProcessHeap(), 0, win_array );
2807 /*******************************************************************
2808 * GetLastActivePopup (USER32.@)
2810 HWND WINAPI GetLastActivePopup( HWND hwnd )
2813 WND *wndPtr =WIN_FindWndPtr(hwnd);
2814 if (!wndPtr) return hwnd;
2815 retval = wndPtr->hwndLastActive;
2816 if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2817 WIN_ReleaseWndPtr(wndPtr);
2822 /*******************************************************************
2825 * Build an array of all parents of a given window, starting with
2826 * the immediate parent. The array must be freed with HeapFree.
2827 * Returns NULL if window is a top-level window.
2829 HWND *WIN_ListParents( HWND hwnd )
2832 HWND current, *list;
2833 int pos = 0, size = 16, count = 0;
2835 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2840 if (!(win = WIN_GetPtr( current ))) goto empty;
2841 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2842 list[pos] = win->parent;
2843 WIN_ReleasePtr( win );
2844 if (!(current = list[pos]))
2846 if (!pos) goto empty;
2849 if (++pos == size - 1)
2851 /* need to grow the list */
2852 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2853 if (!new_list) goto empty;
2859 /* at least one parent belongs to another process, have to query the server */
2864 SERVER_START_REQ( get_window_parents )
2867 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2868 if (!wine_server_call( req )) count = reply->count;
2871 if (!count) goto empty;
2877 HeapFree( GetProcessHeap(), 0, list );
2879 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2883 HeapFree( GetProcessHeap(), 0, list );
2888 /*******************************************************************
2891 * Build an array of the children of a given window. The array must be
2892 * freed with HeapFree. Returns NULL when no windows are found.
2894 HWND *WIN_ListChildren( HWND hwnd )
2896 return list_window_children( hwnd, 0, 0 );
2900 /*******************************************************************
2901 * EnumWindows (USER32.@)
2903 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2909 /* We have to build a list of all windows first, to avoid */
2910 /* unpleasant side-effects, for instance if the callback */
2911 /* function changes the Z-order of the windows. */
2913 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2915 /* Now call the callback function for every window */
2917 iWndsLocks = WIN_SuspendWndsLock();
2918 for (i = 0; list[i]; i++)
2920 /* Make sure that the window still exists */
2921 if (!IsWindow( list[i] )) continue;
2922 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2924 WIN_RestoreWndsLock(iWndsLocks);
2925 HeapFree( GetProcessHeap(), 0, list );
2930 /**********************************************************************
2931 * EnumThreadWindows (USER32.@)
2933 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2938 if (!(list = list_window_children( GetDesktopWindow(), 0, GetCurrentThreadId() )))
2941 /* Now call the callback function for every window */
2943 iWndsLocks = WIN_SuspendWndsLock();
2944 for (i = 0; list[i]; i++)
2945 if (!func( list[i], lParam )) break;
2946 WIN_RestoreWndsLock(iWndsLocks);
2947 HeapFree( GetProcessHeap(), 0, list );
2952 /**********************************************************************
2953 * WIN_EnumChildWindows
2955 * Helper function for EnumChildWindows().
2957 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2962 for ( ; *list; list++)
2964 /* Make sure that the window still exists */
2965 if (!IsWindow( *list )) continue;
2966 /* skip owned windows */
2967 if (GetWindow( *list, GW_OWNER )) continue;
2968 /* Build children list first */
2969 childList = WIN_ListChildren( *list );
2971 ret = func( *list, lParam );
2975 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2976 HeapFree( GetProcessHeap(), 0, childList );
2978 if (!ret) return FALSE;
2984 /**********************************************************************
2985 * EnumChildWindows (USER32.@)
2987 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2992 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2993 iWndsLocks = WIN_SuspendWndsLock();
2994 WIN_EnumChildWindows( list, func, lParam );
2995 WIN_RestoreWndsLock(iWndsLocks);
2996 HeapFree( GetProcessHeap(), 0, list );
3001 /*******************************************************************
3002 * AnyPopup (USER.52)
3004 BOOL16 WINAPI AnyPopup16(void)
3010 /*******************************************************************
3011 * AnyPopup (USER32.@)
3013 BOOL WINAPI AnyPopup(void)
3017 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3019 if (!list) return FALSE;
3020 for (i = 0; list[i]; i++)
3022 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3024 retvalue = (list[i] != 0);
3025 HeapFree( GetProcessHeap(), 0, list );
3030 /*******************************************************************
3031 * FlashWindow (USER32.@)
3033 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3035 WND *wndPtr = WIN_FindWndPtr(hWnd);
3037 TRACE("%04x\n", hWnd);
3039 if (!wndPtr) return FALSE;
3040 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3042 if (wndPtr->dwStyle & WS_MINIMIZE)
3044 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3046 HDC hDC = GetDC(hWnd);
3048 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
3049 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3051 ReleaseDC( hWnd, hDC );
3052 wndPtr->flags |= WIN_NCACTIVATED;
3056 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3057 wndPtr->flags &= ~WIN_NCACTIVATED;
3059 WIN_ReleaseWndPtr(wndPtr);
3065 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3066 else wparam = (hWnd == GetActiveWindow());
3068 WIN_ReleaseWndPtr(wndPtr);
3069 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3075 /*******************************************************************
3076 * GetWindowContextHelpId (USER32.@)
3078 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3081 WND *wnd = WIN_FindWndPtr( hwnd );
3083 retval = wnd->helpContext;
3084 WIN_ReleaseWndPtr(wnd);
3089 /*******************************************************************
3090 * SetWindowContextHelpId (USER32.@)
3092 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3094 WND *wnd = WIN_FindWndPtr( hwnd );
3095 if (!wnd) return FALSE;
3096 wnd->helpContext = id;
3097 WIN_ReleaseWndPtr(wnd);
3102 /*******************************************************************
3105 * recursively find a child that contains spDragInfo->pt point
3106 * and send WM_QUERYDROPOBJECT
3108 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
3110 BOOL16 wParam, bResult = 0;
3112 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3115 if (!ptrDragInfo) return FALSE;
3117 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3119 GetWindowRect(hQueryWnd,&tempRect);
3121 if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
3123 if (!IsIconic( hQueryWnd ))
3125 GetClientRect( hQueryWnd, &tempRect );
3126 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
3128 if (PtInRect( &tempRect, pt))
3131 HWND *list = WIN_ListChildren( hQueryWnd );
3137 for (i = 0; list[i]; i++)
3139 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
3141 GetWindowRect( list[i], &tempRect );
3142 if (PtInRect( &tempRect, pt )) break;
3147 if (IsWindowEnabled( list[i] ))
3148 bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
3150 HeapFree( GetProcessHeap(), 0, list );
3152 if(bResult) return bResult;
3158 ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
3160 ptrDragInfo->hScope = hQueryWnd;
3162 if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
3163 else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
3165 if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3171 /*******************************************************************
3172 * DragDetect (USER32.@)
3174 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3179 rect.left = pt.x - wDragWidth;
3180 rect.right = pt.x + wDragWidth;
3182 rect.top = pt.y - wDragHeight;
3183 rect.bottom = pt.y + wDragHeight;
3189 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3191 if( msg.message == WM_LBUTTONUP )
3196 if( msg.message == WM_MOUSEMOVE )
3199 tmp.x = LOWORD(msg.lParam);
3200 tmp.y = HIWORD(msg.lParam);
3201 if( !PtInRect( &rect, tmp ))
3213 /******************************************************************************
3214 * DragObject (USER.464)
3216 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3217 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3220 LPDRAGINFO16 lpDragInfo;
3222 HCURSOR16 hDragCursor=0, hOldCursor=0, hBummer=0;
3223 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3224 HCURSOR16 hCurrentCursor = 0;
3225 HWND16 hCurrentWnd = 0;
3227 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3228 spDragInfo = K32WOWGlobalLock16(hDragInfo);
3230 if( !lpDragInfo || !spDragInfo ) return 0L;
3232 if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
3234 GlobalFree16(hDragInfo);
3240 if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
3242 GlobalFree16(hDragInfo);
3246 if( hDragCursor == hCursor ) hDragCursor = 0;
3247 else hCursor = hDragCursor;
3249 hOldCursor = SetCursor(hDragCursor);
3252 lpDragInfo->hWnd = hWnd;
3253 lpDragInfo->hScope = 0;
3254 lpDragInfo->wFlags = wObj;
3255 lpDragInfo->hList = szList; /* near pointer! */
3256 lpDragInfo->hOfStruct = hOfStruct;
3264 GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
3266 *(lpDragInfo+1) = *lpDragInfo;
3268 lpDragInfo->pt.x = msg.pt.x;
3269 lpDragInfo->pt.y = msg.pt.y;
3271 /* update DRAGINFO struct */
3272 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3274 if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
3275 hCurrentCursor = hCursor;
3278 hCurrentCursor = hBummer;
3279 lpDragInfo->hScope = 0;
3281 if( hCurrentCursor )
3282 SetCursor(hCurrentCursor);
3284 /* send WM_DRAGLOOP */
3285 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3286 (LPARAM) spDragInfo );
3287 /* send WM_DRAGSELECT or WM_DRAGMOVE */
3288 if( hCurrentWnd != lpDragInfo->hScope )
3291 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3292 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3293 HIWORD(spDragInfo)) );
3294 hCurrentWnd = lpDragInfo->hScope;
3296 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3300 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3302 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3305 ShowCursor( FALSE );
3309 SetCursor( hOldCursor );
3310 if (hDragCursor) DestroyCursor( hDragCursor );
3313 if( hCurrentCursor != hBummer )
3314 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3315 (WPARAM16)hWnd, (LPARAM)spDragInfo );
3318 GlobalFree16(hDragInfo);
3320 return (DWORD)(msg.lParam);
3324 /******************************************************************************
3325 * GetWindowModuleFileNameA (USER32.@)
3327 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3329 FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3330 hwnd, lpszFileName, cchFileNameMax);
3334 /******************************************************************************
3335 * GetWindowModuleFileNameW (USER32.@)
3337 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3339 FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3340 hwnd, lpszFileName, cchFileNameMax);
3344 /******************************************************************************
3345 * GetWindowInfo (USER32.@)
3348 * MS Documentation mentions that pwi->cbSize must be set to SIZEOF(WINDOWINFO)
3349 * this may be because this structure changed over time. If this is the
3350 * the case, then please: FIXME.
3351 * Using the structure described in MSDN for 98/ME/NT(4.0 SP3)/2000/XP.
3353 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3355 WND *wndInfo = NULL;
3356 if (!pwi) return FALSE;
3357 if (pwi->cbSize != sizeof(WINDOWINFO))
3359 FIXME("windowinfo->cbSize != sizeof(WINDOWINFO). Please report\n");
3362 wndInfo = WIN_GetPtr(hwnd);
3363 if (!wndInfo) return FALSE;
3364 if (wndInfo == WND_OTHER_PROCESS)
3366 FIXME("window belong to other process\n");
3370 pwi->rcWindow = wndInfo->rectWindow;
3371 pwi->rcClient = wndInfo->rectClient;
3372 pwi->dwStyle = wndInfo->dwStyle;
3373 pwi->dwExStyle = wndInfo->dwExStyle;
3374 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3375 /* if active WS_ACTIVECAPTION, else 0 */
3377 pwi->cxWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3378 GetSystemMetrics(SM_CXBORDER) : 0);
3379 pwi->cyWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3380 GetSystemMetrics(SM_CYBORDER) : 0);
3381 /* above two: I'm presuming that borders widths are the same
3382 * for each window - so long as its actually using a border.. */
3384 pwi->atomWindowType = GetClassLongA( hwnd, GCW_ATOM );
3385 pwi->wCreatorVersion = GetVersion();
3386 /* Docs say this should be the version that
3387 * CREATED the window. But eh?.. Isn't that just the
3388 * version we are running.. Unless ofcourse its some wacky
3389 * RPC stuff or something */
3391 WIN_ReleasePtr(wndInfo);