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"
30 #include "wine/winbase16.h"
31 #include "wine/winuser16.h"
33 #include "wine/server.h"
34 #include "wine/unicode.h"
39 #include "cursoricon.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(win);
46 WINE_DECLARE_DEBUG_CHANNEL(msg);
48 #define NB_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1)
49 #define USER_HANDLE_TO_INDEX(hwnd) ((LOWORD(hwnd) - 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];
61 /***********************************************************************
62 * create_window_handle
64 * Create a window handle with the server.
66 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom,
67 HINSTANCE instance, WINDOWPROCTYPE type )
71 struct tagCLASS *class = NULL;
72 user_handle_t handle = 0;
75 /* if 16-bit instance, map to module handle */
76 if (instance && !HIWORD(instance))
77 instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
79 SERVER_START_REQ( create_window )
84 req->instance = instance;
85 if (!wine_server_call_err( req ))
87 handle = reply->handle;
88 extra_bytes = reply->extra;
89 class = reply->class_ptr;
96 WARN( "error %ld creating window\n", GetLastError() );
100 if (!(win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
102 SERVER_START_REQ( destroy_window )
104 req->handle = handle;
105 wine_server_call( req );
108 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
114 index = USER_HANDLE_TO_INDEX(handle);
115 assert( index < NB_USER_HANDLES );
116 user_handles[index] = win;
117 win->hwndSelf = handle;
118 win->dwMagic = WND_MAGIC;
120 win->cbWndExtra = extra_bytes;
121 memset( win->wExtra, 0, extra_bytes );
122 CLASS_AddWindow( class, win, type );
127 /***********************************************************************
130 * Free a window handle.
132 static WND *free_window_handle( HWND hwnd )
135 WORD index = USER_HANDLE_TO_INDEX(hwnd);
137 if (index >= NB_USER_HANDLES) return NULL;
139 if ((ptr = user_handles[index]))
141 SERVER_START_REQ( destroy_window )
144 if (!wine_server_call_err( req ))
145 user_handles[index] = NULL;
152 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
157 /*******************************************************************
158 * list_window_children
160 * Build an array of the children of a given window. The array must be
161 * freed with HeapFree. Returns NULL when no windows are found.
163 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
172 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
174 SERVER_START_REQ( get_window_children )
179 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
180 if (!wine_server_call( req )) count = reply->count;
183 if (count && count < size)
188 HeapFree( GetProcessHeap(), 0, list );
190 size = count + 1; /* restart with a large enough buffer */
196 /*******************************************************************
199 static void send_parent_notify( HWND hwnd, UINT msg )
201 if ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD &&
202 !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY))
203 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
204 MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
208 /*******************************************************************
209 * get_server_window_text
211 * Retrieve the window text from the server.
213 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
217 SERVER_START_REQ( get_window_text )
220 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
221 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
224 text[len / sizeof(WCHAR)] = 0;
228 /***********************************************************************
231 * Return a pointer to the WND structure if local to the process,
232 * or WND_OTHER_PROCESS if handle may be valid in other process.
233 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
235 WND *WIN_GetPtr( HWND hwnd )
238 WORD index = USER_HANDLE_TO_INDEX(hwnd);
240 if (index >= NB_USER_HANDLES) return NULL;
243 if ((ptr = user_handles[index]))
245 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
249 else ptr = WND_OTHER_PROCESS;
255 /***********************************************************************
256 * WIN_IsCurrentProcess
258 * Check whether a given window belongs to the current process (and return the full handle).
260 HWND WIN_IsCurrentProcess( HWND hwnd )
265 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
267 WIN_ReleasePtr( ptr );
272 /***********************************************************************
273 * WIN_IsCurrentThread
275 * Check whether a given window belongs to the current thread (and return the full handle).
277 HWND WIN_IsCurrentThread( HWND hwnd )
282 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
284 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
285 WIN_ReleasePtr( ptr );
291 /***********************************************************************
294 * Convert a 16-bit window handle to a full 32-bit handle.
296 HWND WIN_Handle32( HWND16 hwnd16 )
299 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
301 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
302 /* do sign extension for -2 and -3 */
303 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
305 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
307 if (ptr != WND_OTHER_PROCESS)
309 hwnd = ptr->hwndSelf;
310 WIN_ReleasePtr( ptr );
312 else /* may belong to another process */
314 SERVER_START_REQ( get_window_info )
317 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
325 /***********************************************************************
328 * Return a pointer to the WND structure corresponding to a HWND.
330 WND * WIN_FindWndPtr( HWND hwnd )
334 if (!hwnd) return NULL;
336 if ((ptr = WIN_GetPtr( hwnd )))
338 if (ptr != WND_OTHER_PROCESS)
340 /* increment destruction monitoring */
344 if (IsWindow( hwnd )) /* check other processes */
346 ERR( "window %p belongs to other process\n", hwnd );
347 /* DbgBreakPoint(); */
350 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
355 /***********************************************************************
358 * Release the pointer to the WND structure.
360 void WIN_ReleaseWndPtr(WND *wndPtr)
364 /* Decrement destruction monitoring value */
366 /* Check if it's time to release the memory */
367 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
370 free_window_handle( wndPtr->hwndSelf );
372 else if(wndPtr->irefCount < 0)
374 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
375 ERR("forgot a Lock on %p somewhere\n",wndPtr);
377 /* unlock all WND structures for thread safeness */
382 /***********************************************************************
385 * Remove a window from the siblings linked list.
387 void WIN_UnlinkWindow( HWND hwnd )
389 WIN_LinkWindow( hwnd, 0, 0 );
393 /***********************************************************************
396 * Insert a window into the siblings linked list.
397 * The window is inserted after the specified window, which can also
398 * be specified as HWND_TOP or HWND_BOTTOM.
399 * If parent is 0, window is unlinked from the tree.
401 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
403 WND *wndPtr = WIN_GetPtr( hwnd );
406 if (wndPtr == WND_OTHER_PROCESS)
408 if (IsWindow(hwnd)) ERR(" cannot link other process window %p\n", hwnd );
412 SERVER_START_REQ( link_window )
415 req->parent = parent;
416 req->previous = hwndInsertAfter;
417 if (!wine_server_call( req ))
419 if (reply->full_parent) wndPtr->parent = reply->full_parent;
424 WIN_ReleasePtr( wndPtr );
428 /***********************************************************************
431 * Change the owner of a window.
433 HWND WIN_SetOwner( HWND hwnd, HWND owner )
435 WND *win = WIN_GetPtr( hwnd );
439 if (win == WND_OTHER_PROCESS)
441 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
444 SERVER_START_REQ( set_window_owner )
448 if (!wine_server_call( req ))
450 win->owner = reply->full_owner;
451 ret = reply->prev_owner;
455 WIN_ReleasePtr( win );
460 /***********************************************************************
463 * Change the style of a window.
465 LONG WIN_SetStyle( HWND hwnd, LONG style )
469 WND *win = WIN_GetPtr( hwnd );
472 if (win == WND_OTHER_PROCESS)
475 ERR( "cannot set style %lx on other process window %p\n", style, hwnd );
478 if (style == win->dwStyle)
480 WIN_ReleasePtr( win );
483 SERVER_START_REQ( set_window_info )
486 req->flags = SET_WIN_STYLE;
488 req->extra_offset = -1;
489 if ((ok = !wine_server_call( req )))
491 ret = reply->old_style;
492 win->dwStyle = style;
496 WIN_ReleasePtr( win );
497 if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
502 /***********************************************************************
505 * Change the extended style of a window.
507 LONG WIN_SetExStyle( HWND hwnd, LONG style )
510 WND *win = WIN_GetPtr( hwnd );
513 if (win == WND_OTHER_PROCESS)
516 ERR( "cannot set exstyle %lx on other process window %p\n", style, hwnd );
519 if (style == win->dwExStyle)
521 WIN_ReleasePtr( win );
524 SERVER_START_REQ( set_window_info )
527 req->flags = SET_WIN_EXSTYLE;
528 req->ex_style = style;
529 req->extra_offset = -1;
530 if (!wine_server_call( req ))
532 ret = reply->old_ex_style;
533 win->dwExStyle = style;
537 WIN_ReleasePtr( win );
542 /***********************************************************************
545 * Set the window and client rectangles.
547 void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient )
549 WND *win = WIN_GetPtr( hwnd );
553 if (win == WND_OTHER_PROCESS)
555 if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %p\n", hwnd );
558 SERVER_START_REQ( set_window_rectangles )
561 req->window.left = rectWindow->left;
562 req->window.top = rectWindow->top;
563 req->window.right = rectWindow->right;
564 req->window.bottom = rectWindow->bottom;
565 req->client.left = rectClient->left;
566 req->client.top = rectClient->top;
567 req->client.right = rectClient->right;
568 req->client.bottom = rectClient->bottom;
569 ret = !wine_server_call( req );
574 win->rectWindow = *rectWindow;
575 win->rectClient = *rectClient;
577 TRACE( "win %p window (%ld,%ld)-(%ld,%ld) client (%ld,%ld)-(%ld,%ld)\n", hwnd,
578 rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom,
579 rectClient->left, rectClient->top, rectClient->right, rectClient->bottom );
581 WIN_ReleasePtr( win );
585 /***********************************************************************
588 * Get the window and client rectangles.
590 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
592 WND *win = WIN_GetPtr( hwnd );
595 if (!win) return FALSE;
596 if (win == WND_OTHER_PROCESS)
598 SERVER_START_REQ( get_window_rectangles )
601 if ((ret = !wine_server_call( req )))
605 rectWindow->left = reply->window.left;
606 rectWindow->top = reply->window.top;
607 rectWindow->right = reply->window.right;
608 rectWindow->bottom = reply->window.bottom;
612 rectClient->left = reply->client.left;
613 rectClient->top = reply->client.top;
614 rectClient->right = reply->client.right;
615 rectClient->bottom = reply->client.bottom;
623 if (rectWindow) *rectWindow = win->rectWindow;
624 if (rectClient) *rectClient = win->rectClient;
625 WIN_ReleasePtr( win );
631 /***********************************************************************
634 * Destroy storage associated to a window. "Internals" p.358
636 LRESULT WIN_DestroyWindow( HWND hwnd )
641 TRACE("%p\n", hwnd );
643 if (!(hwnd = WIN_IsCurrentThread( hwnd )))
645 ERR( "window doesn't belong to current thread\n" );
649 /* free child windows */
650 if ((list = WIN_ListChildren( hwnd )))
653 for (i = 0; list[i]; i++)
655 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
656 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
658 HeapFree( GetProcessHeap(), 0, list );
662 * Clear the update region to make sure no WM_PAINT messages will be
663 * generated for this window while processing the WM_NCDESTROY.
665 RedrawWindow( hwnd, NULL, 0,
666 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
669 * Send the WM_NCDESTROY to the window being destroyed.
671 SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
673 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
675 WINPOS_CheckInternalPos( hwnd );
676 if( hwnd == GetCapture()) ReleaseCapture();
678 /* free resources associated with the window */
680 TIMER_RemoveWindowTimers( hwnd );
682 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
684 if (!(wndPtr->dwStyle & WS_CHILD))
686 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
687 if (menu) DestroyMenu( menu );
689 if (wndPtr->hSysMenu)
691 DestroyMenu( wndPtr->hSysMenu );
692 wndPtr->hSysMenu = 0;
694 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
695 USER_Driver.pDestroyWindow( hwnd );
696 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
697 wndPtr->class = NULL;
698 wndPtr->dwMagic = 0; /* Mark it as invalid */
699 WIN_ReleaseWndPtr( wndPtr );
703 /***********************************************************************
704 * WIN_DestroyThreadWindows
706 * Destroy all children of 'wnd' owned by the current thread.
707 * Return TRUE if something was done.
709 void WIN_DestroyThreadWindows( HWND hwnd )
714 if (!(list = WIN_ListChildren( hwnd ))) return;
715 for (i = 0; list[i]; i++)
717 if (WIN_IsCurrentThread( list[i] ))
718 DestroyWindow( list[i] );
720 WIN_DestroyThreadWindows( list[i] );
722 HeapFree( GetProcessHeap(), 0, list );
725 /***********************************************************************
726 * WIN_CreateDesktopWindow
728 * Create the desktop window.
730 BOOL WIN_CreateDesktopWindow(void)
736 TRACE("Creating desktop window\n");
738 if (!WINPOS_CreateInternalPosAtom()) return FALSE;
740 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W );
741 if (!pWndDesktop) return FALSE;
742 hwndDesktop = pWndDesktop->hwndSelf;
744 pWndDesktop->tid = 0; /* nobody owns the desktop */
745 pWndDesktop->parent = 0;
746 pWndDesktop->owner = 0;
747 pWndDesktop->text = NULL;
748 pWndDesktop->hrgnUpdate = 0;
749 pWndDesktop->pVScroll = NULL;
750 pWndDesktop->pHScroll = NULL;
751 pWndDesktop->helpContext = 0;
752 pWndDesktop->flags = 0;
753 pWndDesktop->hSysMenu = 0;
755 cs.lpCreateParams = NULL;
761 cs.cx = GetSystemMetrics( SM_CXSCREEN );
762 cs.cy = GetSystemMetrics( SM_CYSCREEN );
763 cs.style = pWndDesktop->dwStyle;
764 cs.dwExStyle = pWndDesktop->dwExStyle;
766 cs.lpszClass = DESKTOP_CLASS_ATOM;
768 SetRect( &rect, 0, 0, cs.cx, cs.cy );
769 WIN_SetRectangles( hwndDesktop, &rect, &rect );
771 SERVER_START_REQ( set_window_info )
773 req->handle = hwndDesktop;
774 req->flags = 0; /* don't set anything, just retrieve */
775 req->extra_offset = -1;
776 wine_server_call( req );
777 pWndDesktop->dwStyle = reply->old_style;
778 pWndDesktop->dwExStyle = reply->old_ex_style;
779 pWndDesktop->hInstance = (HINSTANCE)reply->old_instance;
780 pWndDesktop->userdata = (ULONG_PTR)reply->old_user_data;
781 pWndDesktop->wIDmenu = reply->old_id;
785 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
787 WIN_ReleaseWndPtr( pWndDesktop );
791 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
792 WIN_ReleaseWndPtr( pWndDesktop );
797 /***********************************************************************
800 * Fix the coordinates - Helper for WIN_CreateWindowEx.
801 * returns default show mode in sw.
802 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
804 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
806 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
807 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
809 if (cs->style & (WS_CHILD | WS_POPUP))
811 if (cs->dwExStyle & WS_EX_MDICHILD)
815 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0);
817 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
822 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16 || !cs->cx)
824 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16 || !cs->cy)
829 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
831 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
835 else /* overlapped window */
839 GetStartupInfoA( &info );
841 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
843 /* Never believe Microsoft's documentation... CreateWindowEx doc says
844 * that if an overlapped window is created with WS_VISIBLE style bit
845 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
846 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
849 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
850 * 2) it does not ignore the y parameter as the docs claim; instead, it
851 * uses it as second parameter to ShowWindow() unless y is either
852 * CW_USEDEFAULT or CW_USEDEFAULT16.
854 * The fact that we didn't do 2) caused bogus windows pop up when wine
855 * was running apps that were using this obscure feature. Example -
856 * calc.exe that comes with Win98 (only Win98, it's different from
857 * the one that comes with Win95 and NT)
859 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
860 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
861 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
864 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
866 if (info.dwFlags & STARTF_USESIZE)
868 cs->cx = info.dwXSize;
869 cs->cy = info.dwYSize;
871 else /* if no other hint from the app, pick 3/4 of the screen real estate */
874 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
875 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
876 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
883 /* neither x nor cx are default. Check the y values .
884 * In the trace we see Outlook and Outlook Express using
885 * cy set to CW_USEDEFAULT when opening the address book.
887 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
889 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
890 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
891 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
896 /***********************************************************************
899 static void dump_window_styles( DWORD style, DWORD exstyle )
902 if(style & WS_POPUP) TRACE(" WS_POPUP");
903 if(style & WS_CHILD) TRACE(" WS_CHILD");
904 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
905 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
906 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
907 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
908 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
909 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
910 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
913 if(style & WS_BORDER) TRACE(" WS_BORDER");
914 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
916 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
917 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
918 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
919 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
920 if(style & WS_GROUP) TRACE(" WS_GROUP");
921 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
922 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
923 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
925 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
926 #define DUMPED_STYLES \
946 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
951 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
952 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
953 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
954 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
955 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
956 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
957 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
958 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
959 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
960 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
961 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
962 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
963 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
964 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
965 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
966 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
967 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
968 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
970 #define DUMPED_EX_STYLES \
971 (WS_EX_DLGMODALFRAME | \
973 WS_EX_NOPARENTNOTIFY | \
975 WS_EX_ACCEPTFILES | \
976 WS_EX_TRANSPARENT | \
981 WS_EX_CONTEXTHELP | \
984 WS_EX_LEFTSCROLLBAR | \
985 WS_EX_CONTROLPARENT | \
990 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
992 #undef DUMPED_EX_STYLES
996 /***********************************************************************
999 * Implementation of CreateWindowEx().
1001 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
1002 WINDOWPROCTYPE type )
1006 HWND hwnd, parent, owner, top_child = 0;
1007 BOOL unicode = (type == WIN_PROC_32W);
1009 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1010 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1011 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
1012 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1013 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1015 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1017 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1018 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1020 /* Fix the styles for MDI children */
1021 if (cs->dwExStyle & WS_EX_MDICHILD)
1023 MDICREATESTRUCTA mdi_cs;
1026 wndPtr = WIN_GetPtr(cs->hwndParent);
1027 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
1029 flags = wndPtr->flags;
1030 WIN_ReleasePtr(wndPtr);
1033 if (!(flags & WIN_ISMDICLIENT))
1035 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1039 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1040 * MDICREATESTRUCT members have the originally passed values.
1042 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1043 * have the same layout.
1045 mdi_cs.szClass = cs->lpszClass;
1046 mdi_cs.szTitle = cs->lpszName;
1047 mdi_cs.hOwner = cs->hInstance;
1052 mdi_cs.style = cs->style;
1053 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1055 cs->lpCreateParams = (LPVOID)&mdi_cs;
1057 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1059 if (cs->style & WS_POPUP)
1061 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1064 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1068 cs->style &= ~WS_POPUP;
1069 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1070 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1073 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1076 /* Find the parent window */
1078 parent = GetDesktopWindow();
1081 if (cs->hwndParent == HWND_MESSAGE)
1083 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
1084 * message window (style: WS_POPUP|WS_DISABLED)
1086 FIXME("Parent is HWND_MESSAGE\n");
1088 else if (cs->hwndParent)
1090 /* Make sure parent is valid */
1091 if (!IsWindow( cs->hwndParent ))
1093 WARN("Bad parent %p\n", cs->hwndParent );
1096 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1097 parent = WIN_GetFullHandle(cs->hwndParent);
1099 owner = GetAncestor( cs->hwndParent, GA_ROOT );
1101 else if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1103 WARN("No parent for child window\n" );
1104 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1107 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1109 /* Correct the window styles.
1111 * It affects both the style loaded into the WIN structure and
1112 * passed in the CREATESTRUCT to the WM_[NC]CREATE.
1114 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1115 * why does the user get to set it?
1118 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1119 * tested for WS_POPUP
1121 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1122 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1123 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1124 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1126 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1128 if (!(cs->style & WS_CHILD))
1130 cs->style |= WS_CLIPSIBLINGS;
1131 if (!(cs->style & WS_POPUP))
1132 cs->style |= WS_CAPTION;
1135 /* Create the window structure */
1137 if (!(wndPtr = create_window_handle( parent, owner, classAtom, cs->hInstance, type )))
1139 TRACE("out of memory\n" );
1142 hwnd = wndPtr->hwndSelf;
1144 /* Fill the window structure */
1146 wndPtr->tid = GetCurrentThreadId();
1147 wndPtr->owner = owner;
1148 wndPtr->parent = parent;
1149 wndPtr->hInstance = cs->hInstance;
1150 wndPtr->text = NULL;
1151 wndPtr->hrgnUpdate = 0;
1152 wndPtr->hrgnWnd = 0;
1153 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1154 wndPtr->dwExStyle = cs->dwExStyle;
1155 wndPtr->wIDmenu = 0;
1156 wndPtr->helpContext = 0;
1157 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1158 wndPtr->pVScroll = NULL;
1159 wndPtr->pHScroll = NULL;
1160 wndPtr->userdata = 0;
1162 wndPtr->hIconSmall = 0;
1163 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU) ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1165 if (!(cs->style & (WS_CHILD | WS_POPUP)))
1166 wndPtr->flags |= WIN_NEED_SIZE;
1168 SERVER_START_REQ( set_window_info )
1171 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1172 req->style = wndPtr->dwStyle;
1173 req->ex_style = wndPtr->dwExStyle;
1174 req->instance = (void *)wndPtr->hInstance;
1175 req->extra_offset = -1;
1176 wine_server_call( req );
1180 /* Get class or window DC if needed */
1182 if (wndPtr->clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1184 /* Set the window menu */
1186 if (((wndPtr->dwStyle & (WS_CAPTION|WS_CHILD)) == WS_CAPTION) ||
1187 (wndPtr->dwExStyle & WS_EX_APPWINDOW))
1189 if (cs->hMenu) MENU_SetMenu(hwnd, cs->hMenu);
1192 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1195 if (HIWORD(cs->hInstance))
1196 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1198 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1200 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1204 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1205 WIN_ReleaseWndPtr( wndPtr );
1207 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1209 WIN_DestroyWindow( hwnd );
1213 /* Notify the parent window only */
1215 send_parent_notify( hwnd, WM_CREATE );
1216 if (!IsWindow( hwnd )) return 0;
1218 if (cs->dwExStyle & WS_EX_MDICHILD)
1222 /* Restore current maximized child */
1223 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1225 TRACE("Restoring current maximized child %p\n", top_child);
1226 ShowWindow(top_child, SW_SHOWNOACTIVATE);
1230 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1233 if (cs->style & WS_VISIBLE)
1234 ShowWindow( hwnd, sw );
1236 /* Call WH_SHELL hook */
1238 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1239 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1241 TRACE("created window %p\n", hwnd);
1246 /***********************************************************************
1247 * CreateWindow (USER.41)
1249 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1250 DWORD style, INT16 x, INT16 y, INT16 width,
1251 INT16 height, HWND16 parent, HMENU16 menu,
1252 HINSTANCE16 instance, LPVOID data )
1254 return CreateWindowEx16( 0, className, windowName, style,
1255 x, y, width, height, parent, menu, instance, data );
1259 /***********************************************************************
1260 * CreateWindowEx (USER.452)
1262 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1263 LPCSTR windowName, DWORD style, INT16 x,
1264 INT16 y, INT16 width, INT16 height,
1265 HWND16 parent, HMENU16 menu,
1266 HINSTANCE16 instance, LPVOID 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 /* Fix the coordinates */
1295 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1296 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1297 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1298 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1300 /* Create the window */
1302 cs.lpCreateParams = data;
1303 cs.hInstance = HINSTANCE_32(instance);
1304 cs.hMenu = HMENU_32(menu);
1305 cs.hwndParent = WIN_Handle32( parent );
1307 cs.lpszName = windowName;
1308 cs.lpszClass = className;
1309 cs.dwExStyle = exStyle;
1311 return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1315 /***********************************************************************
1316 * CreateWindowExA (USER32.@)
1318 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1319 LPCSTR windowName, DWORD style, INT x,
1320 INT y, INT width, INT height,
1321 HWND parent, HMENU menu,
1322 HINSTANCE instance, LPVOID data )
1328 /* Find the class atom */
1330 if (HIWORD(className))
1332 if (!(classAtom = GlobalFindAtomA( className )))
1334 ERR( "bad class name %s\n", debugstr_a(className) );
1340 classAtom = LOWORD(className);
1341 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1343 ERR( "bad atom %x\n", classAtom);
1349 /* Create the window */
1351 cs.lpCreateParams = data;
1352 cs.hInstance = instance;
1354 cs.hwndParent = parent;
1360 cs.lpszName = windowName;
1361 cs.lpszClass = className;
1362 cs.dwExStyle = exStyle;
1364 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1368 /***********************************************************************
1369 * CreateWindowExW (USER32.@)
1371 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1372 LPCWSTR windowName, DWORD style, INT x,
1373 INT y, INT width, INT height,
1374 HWND parent, HMENU menu,
1375 HINSTANCE instance, LPVOID data )
1381 /* Find the class atom */
1383 if (HIWORD(className))
1385 if (!(classAtom = GlobalFindAtomW( className )))
1387 ERR( "bad class name %s\n", debugstr_w(className) );
1393 classAtom = LOWORD(className);
1394 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1396 ERR( "bad atom %x\n", classAtom);
1402 /* Create the window */
1404 cs.lpCreateParams = data;
1405 cs.hInstance = instance;
1407 cs.hwndParent = parent;
1413 cs.lpszName = windowName;
1414 cs.lpszClass = className;
1415 cs.dwExStyle = exStyle;
1417 /* Note: we rely on the fact that CREATESTRUCTA and */
1418 /* CREATESTRUCTW have the same layout. */
1419 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1423 /***********************************************************************
1424 * WIN_SendDestroyMsg
1426 static void WIN_SendDestroyMsg( HWND hwnd )
1430 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1432 if (hwnd == info.hwndCaret) DestroyCaret();
1433 if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1435 if (USER_Driver.pResetSelectionOwner)
1436 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1439 * Send the WM_DESTROY to the window.
1441 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1444 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1445 * make sure that the window still exists when we come back.
1452 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1454 /* start from the end (FIXME: is this needed?) */
1455 for (i = 0; pWndArray[i]; i++) ;
1459 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1461 HeapFree( GetProcessHeap(), 0, pWndArray );
1464 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1468 /***********************************************************************
1469 * DestroyWindow (USER32.@)
1471 BOOL WINAPI DestroyWindow( HWND hwnd )
1475 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1477 SetLastError( ERROR_ACCESS_DENIED );
1481 TRACE("(%p)\n", hwnd);
1483 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1484 SendMessageW(GetAncestor(hwnd, GA_PARENT), WM_MDIREFRESHMENU, 0, 0);
1488 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1490 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1494 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1495 send_parent_notify( hwnd, WM_DESTROY );
1497 else if (!GetWindow( hwnd, GW_OWNER ))
1499 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1500 /* FIXME: clean up palette - see "Internals" p.352 */
1503 if (!IsWindow(hwnd)) return TRUE;
1505 if (USER_Driver.pResetSelectionOwner)
1506 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1508 /* Hide the window */
1510 /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1512 ShowWindow( hwnd, SW_HIDE );
1514 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1515 SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1517 if (!IsWindow(hwnd)) return TRUE;
1519 /* Recursively destroy owned windows */
1526 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1529 for (i = 0; list[i]; i++)
1531 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1532 if (WIN_IsCurrentThread( list[i] ))
1534 DestroyWindow( list[i] );
1538 WIN_SetOwner( list[i], 0 );
1540 HeapFree( GetProcessHeap(), 0, list );
1542 if (!got_one) break;
1546 /* Send destroy messages */
1548 WIN_SendDestroyMsg( hwnd );
1549 if (!IsWindow( hwnd )) return TRUE;
1551 if (GetClipboardOwner() == hwnd)
1552 CLIPBOARD_ReleaseOwner();
1554 /* Unlink now so we won't bother with the children later on */
1556 WIN_UnlinkWindow( hwnd );
1558 /* Destroy the window storage */
1560 WIN_DestroyWindow( hwnd );
1565 /***********************************************************************
1566 * CloseWindow (USER32.@)
1568 BOOL WINAPI CloseWindow( HWND hwnd )
1570 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1571 ShowWindow( hwnd, SW_MINIMIZE );
1576 /***********************************************************************
1577 * OpenIcon (USER32.@)
1579 BOOL WINAPI OpenIcon( HWND hwnd )
1581 if (!IsIconic( hwnd )) return FALSE;
1582 ShowWindow( hwnd, SW_SHOWNORMAL );
1587 /***********************************************************************
1590 * Implementation of FindWindow() and FindWindowEx().
1592 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1597 WCHAR *buffer = NULL;
1599 if (!parent) parent = GetDesktopWindow();
1602 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1603 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1606 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1610 child = WIN_GetFullHandle( child );
1611 while (list[i] && list[i] != child) i++;
1612 if (!list[i]) goto done;
1613 i++; /* start from next window */
1620 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1627 if (list) HeapFree( GetProcessHeap(), 0, list );
1628 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1634 /***********************************************************************
1635 * FindWindowA (USER32.@)
1637 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1639 HWND ret = FindWindowExA( 0, 0, className, title );
1640 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1645 /***********************************************************************
1646 * FindWindowExA (USER32.@)
1648 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1649 LPCSTR className, LPCSTR title )
1658 /* If the atom doesn't exist, then no class */
1659 /* with this name exists either. */
1660 if (!(atom = GlobalFindAtomA( className )))
1662 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1666 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1668 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1669 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1670 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1671 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1672 HeapFree( GetProcessHeap(), 0, buffer );
1677 /***********************************************************************
1678 * FindWindowExW (USER32.@)
1680 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1681 LPCWSTR className, LPCWSTR title )
1687 /* If the atom doesn't exist, then no class */
1688 /* with this name exists either. */
1689 if (!(atom = GlobalFindAtomW( className )))
1691 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1695 return WIN_FindWindow( parent, child, atom, title );
1699 /***********************************************************************
1700 * FindWindowW (USER32.@)
1702 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1704 return FindWindowExW( 0, 0, className, title );
1708 /**********************************************************************
1709 * GetDesktopWindow (USER32.@)
1711 HWND WINAPI GetDesktopWindow(void)
1713 if (pWndDesktop) return pWndDesktop->hwndSelf;
1714 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" );
1720 /*******************************************************************
1721 * EnableWindow (USER32.@)
1723 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1730 if (is_broadcast(hwnd))
1732 SetLastError( ERROR_INVALID_PARAMETER );
1736 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1737 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1741 TRACE("( %p, %d )\n", hwnd, enable);
1743 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1744 style = wndPtr->dwStyle;
1745 retvalue = ((style & WS_DISABLED) != 0);
1746 WIN_ReleasePtr( wndPtr );
1748 if (enable && retvalue)
1750 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1751 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1753 else if (!enable && !retvalue)
1755 HWND focus_wnd, capture_wnd;
1757 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1759 WIN_SetStyle( hwnd, style | WS_DISABLED );
1761 focus_wnd = GetFocus();
1762 if (hwnd == focus_wnd || IsChild(hwnd, focus_wnd))
1763 SetFocus( 0 ); /* A disabled window can't have the focus */
1765 capture_wnd = GetCapture();
1766 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1767 ReleaseCapture(); /* A disabled window can't capture the mouse */
1769 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1775 /***********************************************************************
1776 * IsWindowEnabled (USER32.@)
1778 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1780 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1784 /***********************************************************************
1785 * IsWindowUnicode (USER32.@)
1787 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1792 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1793 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1794 WIN_ReleaseWndPtr(wndPtr);
1799 /**********************************************************************
1800 * GetWindowWord (USER32.@)
1802 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1807 WND *wndPtr = WIN_GetPtr( hwnd );
1810 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1813 if (wndPtr == WND_OTHER_PROCESS)
1815 SERVER_START_REQ( set_window_info )
1818 req->flags = 0; /* don't set anything, just retrieve */
1819 req->extra_offset = offset;
1820 req->extra_size = sizeof(retvalue);
1821 if (!wine_server_call_err( req ))
1822 memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
1827 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1829 WARN("Invalid offset %d\n", offset );
1830 SetLastError( ERROR_INVALID_INDEX );
1832 else memcpy( &retvalue, (char *)wndPtr->wExtra + offset, sizeof(retvalue) );
1833 WIN_ReleasePtr( wndPtr );
1839 case GWL_HWNDPARENT:
1840 return GetWindowLongW( hwnd, offset );
1844 LONG ret = GetWindowLongW( hwnd, offset );
1846 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1850 WARN("Invalid offset %d\n", offset );
1856 /**********************************************************************
1857 * SetWindowWord (USER32.@)
1859 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1868 case GWL_HWNDPARENT:
1869 return SetWindowLongW( hwnd, offset, (UINT)newval );
1873 WARN("Invalid offset %d\n", offset );
1874 SetLastError( ERROR_INVALID_INDEX );
1879 wndPtr = WIN_GetPtr( hwnd );
1880 if (wndPtr == WND_OTHER_PROCESS)
1883 FIXME( "set %d <- %x not supported yet on other process window %p\n",
1884 offset, newval, hwnd );
1889 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1893 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1895 WARN("Invalid offset %d\n", offset );
1896 WIN_ReleasePtr(wndPtr);
1897 SetLastError( ERROR_INVALID_INDEX );
1901 SERVER_START_REQ( set_window_info )
1904 req->flags = SET_WIN_EXTRA;
1905 req->extra_offset = offset;
1906 req->extra_size = sizeof(newval);
1907 memcpy( &req->extra_value, &newval, sizeof(newval) );
1908 if (!wine_server_call_err( req ))
1910 void *ptr = (char *)wndPtr->wExtra + offset;
1911 memcpy( &retval, ptr, sizeof(retval) );
1912 memcpy( ptr, &newval, sizeof(newval) );
1916 WIN_ReleasePtr( wndPtr );
1921 /**********************************************************************
1924 * Helper function for GetWindowLong().
1926 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1931 if (offset == GWL_HWNDPARENT)
1933 HWND parent = GetAncestor( hwnd, GA_PARENT );
1934 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1935 return (LONG)parent;
1938 if (!(wndPtr = WIN_GetPtr( hwnd )))
1940 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1944 if (wndPtr == WND_OTHER_PROCESS)
1946 if (offset == GWL_WNDPROC)
1948 SetLastError( ERROR_ACCESS_DENIED );
1951 SERVER_START_REQ( set_window_info )
1954 req->flags = 0; /* don't set anything, just retrieve */
1955 req->extra_offset = (offset >= 0) ? offset : -1;
1956 req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
1957 if (!wine_server_call_err( req ))
1961 case GWL_STYLE: retvalue = reply->old_style; break;
1962 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1963 case GWL_ID: retvalue = reply->old_id; break;
1964 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1965 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1967 if (offset >= 0) retvalue = reply->old_extra_value;
1968 else SetLastError( ERROR_INVALID_INDEX );
1977 /* now we have a valid wndPtr */
1981 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1984 * Some programs try to access last element from 16 bit
1985 * code using illegal offset value. Hopefully this is
1986 * what those programs really expect.
1988 if (type == WIN_PROC_16 &&
1989 wndPtr->cbWndExtra >= 4 &&
1990 offset == wndPtr->cbWndExtra - sizeof(WORD))
1992 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1994 ERR( "- replaced invalid offset %d with %d\n",
1997 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1998 WIN_ReleasePtr( wndPtr );
2001 WARN("Invalid offset %d\n", offset );
2002 WIN_ReleasePtr( wndPtr );
2003 SetLastError( ERROR_INVALID_INDEX );
2006 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
2007 /* Special case for dialog window procedure */
2008 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2009 retvalue = (LONG)WINPROC_GetProc( (WNDPROC)retvalue, type );
2010 WIN_ReleasePtr( wndPtr );
2016 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
2017 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2018 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2019 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
2020 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
2021 case GWL_HINSTANCE: retvalue = (LONG)wndPtr->hInstance; break;
2023 WARN("Unknown offset %d\n", offset );
2024 SetLastError( ERROR_INVALID_INDEX );
2027 WIN_ReleasePtr(wndPtr);
2032 /**********************************************************************
2035 * Helper function for SetWindowLong().
2037 * 0 is the failure code. However, in the case of failure SetLastError
2038 * must be set to distinguish between a 0 return value and a failure.
2040 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
2041 WINDOWPROCTYPE type )
2048 TRACE( "%p %d %lx %x\n", hwnd, offset, newval, type );
2050 if (is_broadcast(hwnd))
2052 SetLastError( ERROR_INVALID_PARAMETER );
2055 if (!WIN_IsCurrentProcess( hwnd ))
2057 if (offset == GWL_WNDPROC)
2059 SetLastError( ERROR_ACCESS_DENIED );
2062 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
2065 wndPtr = WIN_GetPtr( hwnd );
2066 if (wndPtr->hwndSelf == GetDesktopWindow())
2068 /* can't change anything on the desktop window */
2069 WIN_ReleasePtr( wndPtr );
2070 SetLastError( ERROR_ACCESS_DENIED );
2074 /* first some special cases */
2080 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2081 style.styleNew = newval;
2082 WIN_ReleasePtr( wndPtr );
2083 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2084 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2085 newval = style.styleNew;
2087 case GWL_HWNDPARENT:
2088 if (wndPtr->parent == GetDesktopWindow())
2090 WIN_ReleasePtr( wndPtr );
2091 return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
2095 WIN_ReleasePtr( wndPtr );
2096 return (LONG)SetParent( hwnd, (HWND)newval );
2099 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2100 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2101 WIN_ReleasePtr( wndPtr );
2108 if ((wndPtr->cbWndExtra + sizeof(LONG) >= DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2110 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWL_DLGPROC);
2111 retval = (LONG)WINPROC_GetProc( *ptr, type );
2112 WINPROC_SetProc( ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2113 WIN_ReleasePtr( wndPtr );
2118 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2120 WARN("Invalid offset %d\n", offset );
2121 WIN_ReleasePtr( wndPtr );
2122 SetLastError( ERROR_INVALID_INDEX );
2127 LONG *ptr = (LONG *)((char *)wndPtr->wExtra + offset);
2128 if (*ptr == newval) /* already set to the same value */
2130 WIN_ReleasePtr( wndPtr );
2137 SERVER_START_REQ( set_window_info )
2140 req->extra_offset = -1;
2144 req->flags = SET_WIN_STYLE;
2145 req->style = newval;
2148 req->flags = SET_WIN_EXSTYLE;
2149 req->ex_style = newval;
2152 req->flags = SET_WIN_ID;
2156 req->flags = SET_WIN_INSTANCE;
2157 req->instance = (void *)newval;
2160 req->flags = SET_WIN_USERDATA;
2161 req->user_data = (void *)newval;
2164 req->flags = SET_WIN_EXTRA;
2165 req->extra_offset = offset;
2166 req->extra_size = sizeof(newval);
2167 memcpy( &req->extra_value, &newval, sizeof(newval) );
2169 if ((ok = !wine_server_call_err( req )))
2174 wndPtr->dwStyle = newval;
2175 retval = reply->old_style;
2178 wndPtr->dwExStyle = newval;
2179 retval = reply->old_ex_style;
2182 wndPtr->wIDmenu = newval;
2183 retval = reply->old_id;
2186 wndPtr->hInstance = (HINSTANCE)newval;
2187 retval = (ULONG_PTR)reply->old_instance;
2190 wndPtr->userdata = newval;
2191 retval = (ULONG_PTR)reply->old_user_data;
2195 void *ptr = (char *)wndPtr->wExtra + offset;
2196 memcpy( &retval, ptr, sizeof(retval) );
2197 memcpy( ptr, &newval, sizeof(newval) );
2204 WIN_ReleasePtr( wndPtr );
2208 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2209 USER_Driver.pSetWindowStyle( hwnd, retval );
2211 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2212 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2218 /**********************************************************************
2219 * GetWindowLong (USER.135)
2221 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2223 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2227 /**********************************************************************
2228 * GetWindowLongA (USER32.@)
2230 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2232 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2236 /**********************************************************************
2237 * GetWindowLongW (USER32.@)
2239 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2241 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2245 /**********************************************************************
2246 * SetWindowLong (USER.136)
2248 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2250 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2254 /**********************************************************************
2255 * SetWindowLongA (USER32.@)
2257 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2259 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2263 /**********************************************************************
2264 * SetWindowLongW (USER32.@) Set window attribute
2266 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2267 * value in a window's extra memory.
2269 * The _hwnd_ parameter specifies the window. is the handle to a
2270 * window that has extra memory. The _newval_ parameter contains the
2271 * new attribute or extra memory value. If positive, the _offset_
2272 * parameter is the byte-addressed location in the window's extra
2273 * memory to set. If negative, _offset_ specifies the window
2274 * attribute to set, and should be one of the following values:
2276 * GWL_EXSTYLE The window's extended window style
2278 * GWL_STYLE The window's window style.
2280 * GWL_WNDPROC Pointer to the window's window procedure.
2282 * GWL_HINSTANCE The window's pplication instance handle.
2284 * GWL_ID The window's identifier.
2286 * GWL_USERDATA The window's user-specified data.
2288 * If the window is a dialog box, the _offset_ parameter can be one of
2289 * the following values:
2291 * DWL_DLGPROC The address of the window's dialog box procedure.
2293 * DWL_MSGRESULT The return value of a message
2294 * that the dialog box procedure processed.
2296 * DWL_USER Application specific information.
2300 * If successful, returns the previous value located at _offset_. Otherwise,
2305 * Extra memory for a window class is specified by a nonzero cbWndExtra
2306 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2307 * time of class creation.
2309 * Using GWL_WNDPROC to set a new window procedure effectively creates
2310 * a window subclass. Use CallWindowProc() in the new windows procedure
2311 * to pass messages to the superclass's window procedure.
2313 * The user data is reserved for use by the application which created
2316 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2317 * instead, call the EnableWindow() function to change the window's
2320 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2321 * SetParent() instead.
2324 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2325 * it sends WM_STYLECHANGING before changing the settings
2326 * and WM_STYLECHANGED afterwards.
2327 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2329 LONG WINAPI SetWindowLongW(
2330 HWND hwnd, /* [in] window to alter */
2331 INT offset, /* [in] offset, in bytes, of location to alter */
2332 LONG newval /* [in] new value of location */
2334 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2338 /*******************************************************************
2339 * GetWindowTextA (USER32.@)
2341 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2345 if (WIN_IsCurrentProcess( hwnd ))
2346 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2348 /* when window belongs to other process, don't send a message */
2349 if (nMaxCount <= 0) return 0;
2350 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2351 get_server_window_text( hwnd, buffer, nMaxCount );
2352 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2353 lpString[nMaxCount-1] = 0;
2354 HeapFree( GetProcessHeap(), 0, buffer );
2355 return strlen(lpString);
2359 /*******************************************************************
2360 * InternalGetWindowText (USER32.@)
2362 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2366 if (nMaxCount <= 0) return 0;
2367 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2368 if (win != WND_OTHER_PROCESS)
2370 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2371 else lpString[0] = 0;
2372 WIN_ReleasePtr( win );
2376 get_server_window_text( hwnd, lpString, nMaxCount );
2378 return strlenW(lpString);
2382 /*******************************************************************
2383 * GetWindowTextW (USER32.@)
2385 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2387 if (WIN_IsCurrentProcess( hwnd ))
2388 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2390 /* when window belongs to other process, don't send a message */
2391 if (nMaxCount <= 0) return 0;
2392 get_server_window_text( hwnd, lpString, nMaxCount );
2393 return strlenW(lpString);
2397 /*******************************************************************
2398 * SetWindowText (USER32.@)
2399 * SetWindowTextA (USER32.@)
2401 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2403 if (is_broadcast(hwnd))
2405 SetLastError( ERROR_INVALID_PARAMETER );
2408 if (!WIN_IsCurrentProcess( hwnd ))
2410 FIXME( "cannot set text %s of other process window %p\n", debugstr_a(lpString), hwnd );
2411 SetLastError( ERROR_ACCESS_DENIED );
2414 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2418 /*******************************************************************
2419 * SetWindowTextW (USER32.@)
2421 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2423 if (is_broadcast(hwnd))
2425 SetLastError( ERROR_INVALID_PARAMETER );
2428 if (!WIN_IsCurrentProcess( hwnd ))
2430 FIXME( "cannot set text %s of other process window %p\n", debugstr_w(lpString), hwnd );
2431 SetLastError( ERROR_ACCESS_DENIED );
2434 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2438 /*******************************************************************
2439 * GetWindowTextLengthA (USER32.@)
2441 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2443 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2446 /*******************************************************************
2447 * GetWindowTextLengthW (USER32.@)
2449 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2451 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2455 /*******************************************************************
2456 * IsWindow (USER32.@)
2458 BOOL WINAPI IsWindow( HWND hwnd )
2463 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2465 if (ptr != WND_OTHER_PROCESS)
2467 WIN_ReleasePtr( ptr );
2471 /* check other processes */
2472 SERVER_START_REQ( get_window_info )
2475 ret = !wine_server_call_err( req );
2482 /***********************************************************************
2483 * GetWindowThreadProcessId (USER32.@)
2485 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2490 if (!(ptr = WIN_GetPtr( hwnd )))
2492 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2496 if (ptr != WND_OTHER_PROCESS)
2498 /* got a valid window */
2500 if (process) *process = GetCurrentProcessId();
2501 WIN_ReleasePtr( ptr );
2505 /* check other processes */
2506 SERVER_START_REQ( get_window_info )
2509 if (!wine_server_call_err( req ))
2511 tid = (DWORD)reply->tid;
2512 if (process) *process = (DWORD)reply->pid;
2520 /*****************************************************************
2521 * GetParent (USER32.@)
2523 HWND WINAPI GetParent( HWND hwnd )
2528 if (!(wndPtr = WIN_GetPtr( hwnd )))
2530 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2533 if (wndPtr == WND_OTHER_PROCESS)
2535 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2536 if (style & (WS_POPUP | WS_CHILD))
2538 SERVER_START_REQ( get_window_tree )
2541 if (!wine_server_call_err( req ))
2543 if (style & WS_POPUP) retvalue = reply->owner;
2544 else if (style & WS_CHILD) retvalue = reply->parent;
2552 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2553 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2554 WIN_ReleasePtr( wndPtr );
2560 /*****************************************************************
2561 * GetAncestor (USER32.@)
2563 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2566 HWND *list, ret = 0;
2571 if (!(win = WIN_GetPtr( hwnd )))
2573 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2576 if (win != WND_OTHER_PROCESS)
2579 WIN_ReleasePtr( win );
2581 else /* need to query the server */
2583 SERVER_START_REQ( get_window_tree )
2586 if (!wine_server_call_err( req )) ret = reply->parent;
2593 if (!(list = WIN_ListParents( hwnd ))) return 0;
2595 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2599 while (list[count]) count++;
2600 ret = list[count - 2]; /* get the one before the desktop */
2602 HeapFree( GetProcessHeap(), 0, list );
2606 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2609 HWND parent = GetParent( ret );
2619 /*****************************************************************
2620 * SetParent (USER32.@)
2622 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2625 HWND retvalue, full_handle;
2628 if (is_broadcast(hwnd) || is_broadcast(parent))
2630 SetLastError(ERROR_INVALID_PARAMETER);
2634 if (!parent) parent = GetDesktopWindow();
2635 else parent = WIN_GetFullHandle( parent );
2637 if (!IsWindow( parent ))
2639 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2643 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2644 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2648 if (USER_Driver.pSetParent)
2649 return USER_Driver.pSetParent( hwnd, parent );
2651 /* Windows hides the window first, then shows it again
2652 * including the WM_SHOWWINDOW messages and all */
2653 was_visible = ShowWindow( hwnd, SW_HIDE );
2655 if (!IsWindow( parent )) return 0;
2656 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2658 retvalue = wndPtr->parent; /* old parent */
2659 if (parent != retvalue)
2661 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2663 if (parent != GetDesktopWindow()) /* a child window */
2665 if (!(wndPtr->dwStyle & WS_CHILD))
2667 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2668 if (menu) DestroyMenu( menu );
2672 WIN_ReleasePtr( wndPtr );
2674 /* SetParent additionally needs to make hwnd the topmost window
2675 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2676 WM_WINDOWPOSCHANGED notification messages.
2678 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2679 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2680 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2681 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2686 /*******************************************************************
2687 * IsChild (USER32.@)
2689 BOOL WINAPI IsChild( HWND parent, HWND child )
2691 HWND *list = WIN_ListParents( child );
2695 if (!list) return FALSE;
2696 parent = WIN_GetFullHandle( parent );
2697 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2698 ret = (list[i] != 0);
2699 HeapFree( GetProcessHeap(), 0, list );
2704 /***********************************************************************
2705 * IsWindowVisible (USER32.@)
2707 BOOL WINAPI IsWindowVisible( HWND hwnd )
2713 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2714 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2715 for (i = 0; list[i]; i++)
2716 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2718 HeapFree( GetProcessHeap(), 0, list );
2723 /***********************************************************************
2724 * WIN_IsWindowDrawable
2726 * hwnd is drawable when it is visible, all parents are not
2727 * minimized, and it is itself not minimized unless we are
2728 * trying to draw its default class icon.
2730 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2735 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2737 if (!(style & WS_VISIBLE)) return FALSE;
2738 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2740 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2741 for (i = 0; list[i]; i++)
2742 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2745 HeapFree( GetProcessHeap(), 0, list );
2750 /*******************************************************************
2751 * GetTopWindow (USER32.@)
2753 HWND WINAPI GetTopWindow( HWND hwnd )
2755 if (!hwnd) hwnd = GetDesktopWindow();
2756 return GetWindow( hwnd, GW_CHILD );
2760 /*******************************************************************
2761 * GetWindow (USER32.@)
2763 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2767 if (rel == GW_OWNER) /* this one may be available locally */
2769 WND *wndPtr = WIN_GetPtr( hwnd );
2772 SetLastError( ERROR_INVALID_HANDLE );
2775 if (wndPtr != WND_OTHER_PROCESS)
2777 retval = wndPtr->owner;
2778 WIN_ReleasePtr( wndPtr );
2781 /* else fall through to server call */
2784 SERVER_START_REQ( get_window_tree )
2787 if (!wine_server_call_err( req ))
2792 retval = reply->first_sibling;
2795 retval = reply->last_sibling;
2798 retval = reply->next_sibling;
2801 retval = reply->prev_sibling;
2804 retval = reply->owner;
2807 retval = reply->first_child;
2817 /***********************************************************************
2818 * WIN_InternalShowOwnedPopups
2820 * Internal version of ShowOwnedPopups; Wine functions should use this
2821 * to avoid interfering with application calls to ShowOwnedPopups
2822 * and to make sure the application can't prevent showing/hiding.
2824 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2828 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2832 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2834 if (!win_array) return TRUE;
2837 * Show windows Lowest first, Highest last to preserve Z-Order
2839 while (win_array[count]) count++;
2840 while (--count >= 0)
2842 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2843 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2845 if (pWnd->dwStyle & WS_POPUP)
2849 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2850 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2853 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2855 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2856 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2861 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2862 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2863 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2866 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2868 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2869 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2870 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2874 WIN_ReleaseWndPtr( pWnd );
2876 HeapFree( GetProcessHeap(), 0, win_array );
2881 /*******************************************************************
2882 * ShowOwnedPopups (USER32.@)
2884 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2888 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2890 if (!win_array) return TRUE;
2892 while (win_array[count]) count++;
2893 while (--count >= 0)
2895 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2896 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2898 if (pWnd->dwStyle & WS_POPUP)
2902 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2904 /* In Windows, ShowOwnedPopups(TRUE) generates
2905 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2906 * regardless of the state of the owner
2908 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2909 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2914 if (IsWindowVisible(pWnd->hwndSelf))
2916 /* In Windows, ShowOwnedPopups(FALSE) generates
2917 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2918 * regardless of the state of the owner
2920 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2921 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2925 WIN_ReleaseWndPtr( pWnd );
2927 HeapFree( GetProcessHeap(), 0, win_array );
2932 /*******************************************************************
2933 * GetLastActivePopup (USER32.@)
2935 HWND WINAPI GetLastActivePopup( HWND hwnd )
2939 SERVER_START_REQ( get_window_info )
2942 if (!wine_server_call_err( req )) retval = reply->last_active;
2949 /*******************************************************************
2952 * Build an array of all parents of a given window, starting with
2953 * the immediate parent. The array must be freed with HeapFree.
2954 * Returns NULL if window is a top-level window.
2956 HWND *WIN_ListParents( HWND hwnd )
2959 HWND current, *list;
2960 int pos = 0, size = 16, count = 0;
2962 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2967 if (!(win = WIN_GetPtr( current ))) goto empty;
2968 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2969 list[pos] = win->parent;
2970 WIN_ReleasePtr( win );
2971 if (!(current = list[pos]))
2973 if (!pos) goto empty;
2976 if (++pos == size - 1)
2978 /* need to grow the list */
2979 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2980 if (!new_list) goto empty;
2986 /* at least one parent belongs to another process, have to query the server */
2991 SERVER_START_REQ( get_window_parents )
2994 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2995 if (!wine_server_call( req )) count = reply->count;
2998 if (!count) goto empty;
3004 HeapFree( GetProcessHeap(), 0, list );
3006 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
3010 HeapFree( GetProcessHeap(), 0, list );
3015 /*******************************************************************
3018 * Build an array of the children of a given window. The array must be
3019 * freed with HeapFree. Returns NULL when no windows are found.
3021 HWND *WIN_ListChildren( HWND hwnd )
3023 return list_window_children( hwnd, 0, 0 );
3027 /*******************************************************************
3028 * EnumWindows (USER32.@)
3030 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3036 /* We have to build a list of all windows first, to avoid */
3037 /* unpleasant side-effects, for instance if the callback */
3038 /* function changes the Z-order of the windows. */
3040 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3042 /* Now call the callback function for every window */
3044 iWndsLocks = WIN_SuspendWndsLock();
3045 for (i = 0; list[i]; i++)
3047 /* Make sure that the window still exists */
3048 if (!IsWindow( list[i] )) continue;
3049 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3051 WIN_RestoreWndsLock(iWndsLocks);
3052 HeapFree( GetProcessHeap(), 0, list );
3057 /**********************************************************************
3058 * EnumThreadWindows (USER32.@)
3060 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3065 if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
3067 /* Now call the callback function for every window */
3069 iWndsLocks = WIN_SuspendWndsLock();
3070 for (i = 0; list[i]; i++)
3071 if (!func( list[i], lParam )) break;
3072 WIN_RestoreWndsLock(iWndsLocks);
3073 HeapFree( GetProcessHeap(), 0, list );
3078 /**********************************************************************
3079 * WIN_EnumChildWindows
3081 * Helper function for EnumChildWindows().
3083 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3088 for ( ; *list; list++)
3090 /* Make sure that the window still exists */
3091 if (!IsWindow( *list )) continue;
3092 /* skip owned windows */
3093 if (GetWindow( *list, GW_OWNER )) continue;
3094 /* Build children list first */
3095 childList = WIN_ListChildren( *list );
3097 ret = func( *list, lParam );
3101 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3102 HeapFree( GetProcessHeap(), 0, childList );
3104 if (!ret) return FALSE;
3110 /**********************************************************************
3111 * EnumChildWindows (USER32.@)
3113 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3118 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3119 iWndsLocks = WIN_SuspendWndsLock();
3120 WIN_EnumChildWindows( list, func, lParam );
3121 WIN_RestoreWndsLock(iWndsLocks);
3122 HeapFree( GetProcessHeap(), 0, list );
3127 /*******************************************************************
3128 * AnyPopup (USER.52)
3130 BOOL16 WINAPI AnyPopup16(void)
3136 /*******************************************************************
3137 * AnyPopup (USER32.@)
3139 BOOL WINAPI AnyPopup(void)
3143 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3145 if (!list) return FALSE;
3146 for (i = 0; list[i]; i++)
3148 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3150 retvalue = (list[i] != 0);
3151 HeapFree( GetProcessHeap(), 0, list );
3156 /*******************************************************************
3157 * FlashWindow (USER32.@)
3159 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3161 WND *wndPtr = WIN_FindWndPtr(hWnd);
3163 TRACE("%p\n", hWnd);
3165 if (!wndPtr) return FALSE;
3166 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3168 if (wndPtr->dwStyle & WS_MINIMIZE)
3170 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3172 HDC hDC = GetDC(hWnd);
3174 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 ))
3175 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3177 ReleaseDC( hWnd, hDC );
3178 wndPtr->flags |= WIN_NCACTIVATED;
3182 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3183 wndPtr->flags &= ~WIN_NCACTIVATED;
3185 WIN_ReleaseWndPtr(wndPtr);
3191 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3192 else wparam = (hWnd == GetForegroundWindow());
3194 WIN_ReleaseWndPtr(wndPtr);
3195 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3200 /*******************************************************************
3201 * FlashWindowEx (USER32.@)
3203 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3205 FIXME("%p\n", pfwi);
3209 /*******************************************************************
3210 * GetWindowContextHelpId (USER32.@)
3212 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3215 WND *wnd = WIN_FindWndPtr( hwnd );
3217 retval = wnd->helpContext;
3218 WIN_ReleaseWndPtr(wnd);
3223 /*******************************************************************
3224 * SetWindowContextHelpId (USER32.@)
3226 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3228 WND *wnd = WIN_FindWndPtr( hwnd );
3229 if (!wnd) return FALSE;
3230 wnd->helpContext = id;
3231 WIN_ReleaseWndPtr(wnd);
3236 /*******************************************************************
3237 * DragDetect (USER32.@)
3239 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3244 rect.left = pt.x - wDragWidth;
3245 rect.right = pt.x + wDragWidth;
3247 rect.top = pt.y - wDragHeight;
3248 rect.bottom = pt.y + wDragHeight;
3254 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3256 if( msg.message == WM_LBUTTONUP )
3261 if( msg.message == WM_MOUSEMOVE )
3264 tmp.x = LOWORD(msg.lParam);
3265 tmp.y = HIWORD(msg.lParam);
3266 if( !PtInRect( &rect, tmp ))
3278 /******************************************************************************
3279 * GetWindowModuleFileNameA (USER32.@)
3281 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3283 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3284 hwnd, lpszFileName, cchFileNameMax);
3288 /******************************************************************************
3289 * GetWindowModuleFileNameW (USER32.@)
3291 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3293 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3294 hwnd, lpszFileName, cchFileNameMax);
3298 /******************************************************************************
3299 * GetWindowInfo (USER32.@)
3301 * Note: tests show that Windows doesn't check cbSize of the structure.
3303 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3305 if (!pwi) return FALSE;
3306 if (!IsWindow(hwnd)) return FALSE;
3308 GetWindowRect(hwnd, &pwi->rcWindow);
3309 GetClientRect(hwnd, &pwi->rcClient);
3310 /* translate to screen coordinates */
3311 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3313 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3314 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3315 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3317 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3318 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3320 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3321 pwi->wCreatorVersion = 0x0400;