Make DestroyWindow() not mess with a window focus, this should be
[wine.git] / windows / win.c
blob044d1fa35edeb5830f604e2f5c8125e94ef3236e
1 /*
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wine/winbase16.h"
31 #include "wine/winuser16.h"
32 #include "wownt32.h"
33 #include "wine/server.h"
34 #include "wine/unicode.h"
35 #include "win.h"
36 #include "user.h"
37 #include "dce.h"
38 #include "controls.h"
39 #include "cursoricon.h"
40 #include "message.h"
41 #include "winpos.h"
42 #include "winerror.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)
50 /**********************************************************************/
52 /* Desktop window */
53 static WND *pWndDesktop = NULL;
55 static WORD wDragWidth = 4;
56 static WORD wDragHeight= 3;
58 static void *user_handles[NB_USER_HANDLES];
60 /***********************************************************************
61 * create_window_handle
63 * Create a window handle with the server.
65 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom,
66 HINSTANCE instance, WINDOWPROCTYPE type )
68 WORD index;
69 WND *win;
70 struct tagCLASS *class = NULL;
71 user_handle_t handle = 0;
72 int extra_bytes = 0;
74 /* if 16-bit instance, map to module handle */
75 if (instance && !HIWORD(instance))
76 instance = HINSTANCE_32(GetExePtr(HINSTANCE_16(instance)));
78 SERVER_START_REQ( create_window )
80 req->parent = parent;
81 req->owner = owner;
82 req->atom = atom;
83 req->instance = instance;
84 if (!wine_server_call_err( req ))
86 handle = reply->handle;
87 extra_bytes = reply->extra;
88 class = reply->class_ptr;
91 SERVER_END_REQ;
93 if (!handle)
95 WARN( "error %ld creating window\n", GetLastError() );
96 return NULL;
99 if (!(win = HeapAlloc( GetProcessHeap(), 0, sizeof(WND) + extra_bytes - sizeof(win->wExtra) )))
101 SERVER_START_REQ( destroy_window )
103 req->handle = handle;
104 wine_server_call( req );
106 SERVER_END_REQ;
107 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
108 return NULL;
111 USER_Lock();
113 index = LOWORD(handle) - FIRST_USER_HANDLE;
114 assert( index < NB_USER_HANDLES );
115 user_handles[index] = win;
116 win->hwndSelf = handle;
117 win->dwMagic = WND_MAGIC;
118 win->irefCount = 1;
119 win->cbWndExtra = extra_bytes;
120 memset( win->wExtra, 0, extra_bytes );
121 CLASS_AddWindow( class, win, type );
122 return win;
126 /***********************************************************************
127 * free_window_handle
129 * Free a window handle.
131 static WND *free_window_handle( HWND hwnd )
133 WND *ptr;
134 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
136 if (index >= NB_USER_HANDLES) return NULL;
137 USER_Lock();
138 if ((ptr = user_handles[index]))
140 SERVER_START_REQ( destroy_window )
142 req->handle = hwnd;
143 if (!wine_server_call_err( req ))
144 user_handles[index] = NULL;
145 else
146 ptr = NULL;
148 SERVER_END_REQ;
150 USER_Unlock();
151 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
152 return ptr;
156 /*******************************************************************
157 * list_window_children
159 * Build an array of the children of a given window. The array must be
160 * freed with HeapFree. Returns NULL when no windows are found.
162 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
164 HWND *list;
165 int size = 32;
167 for (;;)
169 int count = 0;
171 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
173 SERVER_START_REQ( get_window_children )
175 req->parent = hwnd;
176 req->atom = atom;
177 req->tid = tid;
178 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
179 if (!wine_server_call( req )) count = reply->count;
181 SERVER_END_REQ;
182 if (count && count < size)
184 list[count] = 0;
185 return list;
187 HeapFree( GetProcessHeap(), 0, list );
188 if (!count) break;
189 size = count + 1; /* restart with a large enough buffer */
191 return NULL;
195 /*******************************************************************
196 * send_parent_notify
198 static void send_parent_notify( HWND hwnd, UINT msg )
200 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) return;
201 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) return;
202 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
203 MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
207 /*******************************************************************
208 * get_server_window_text
210 * Retrieve the window text from the server.
212 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
214 size_t len = 0;
216 SERVER_START_REQ( get_window_text )
218 req->handle = hwnd;
219 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
220 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
222 SERVER_END_REQ;
223 text[len / sizeof(WCHAR)] = 0;
227 /***********************************************************************
228 * WIN_GetPtr
230 * Return a pointer to the WND structure if local to the process,
231 * or WND_OTHER_PROCESS if handle may be valid in other process.
232 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
234 WND *WIN_GetPtr( HWND hwnd )
236 WND * ptr;
237 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
239 if (index >= NB_USER_HANDLES) return NULL;
241 USER_Lock();
242 if ((ptr = user_handles[index]))
244 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
245 return ptr;
246 ptr = NULL;
248 else ptr = WND_OTHER_PROCESS;
249 USER_Unlock();
250 return ptr;
254 /***********************************************************************
255 * WIN_IsCurrentProcess
257 * Check whether a given window belongs to the current process (and return the full handle).
259 HWND WIN_IsCurrentProcess( HWND hwnd )
261 WND *ptr;
262 HWND ret;
264 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
265 ret = ptr->hwndSelf;
266 WIN_ReleasePtr( ptr );
267 return ret;
271 /***********************************************************************
272 * WIN_IsCurrentThread
274 * Check whether a given window belongs to the current thread (and return the full handle).
276 HWND WIN_IsCurrentThread( HWND hwnd )
278 WND *ptr;
279 HWND ret = 0;
281 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
283 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
284 WIN_ReleasePtr( ptr );
286 return ret;
290 /***********************************************************************
291 * WIN_Handle32
293 * Convert a 16-bit window handle to a full 32-bit handle.
295 HWND WIN_Handle32( HWND16 hwnd16 )
297 WND *ptr;
298 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
300 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
301 /* do sign extension for -2 and -3 */
302 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
304 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
306 if (ptr != WND_OTHER_PROCESS)
308 hwnd = ptr->hwndSelf;
309 WIN_ReleasePtr( ptr );
311 else /* may belong to another process */
313 SERVER_START_REQ( get_window_info )
315 req->handle = hwnd;
316 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
318 SERVER_END_REQ;
320 return hwnd;
324 /***********************************************************************
325 * WIN_FindWndPtr
327 * Return a pointer to the WND structure corresponding to a HWND.
329 WND * WIN_FindWndPtr( HWND hwnd )
331 WND * ptr;
333 if (!hwnd) return NULL;
335 if ((ptr = WIN_GetPtr( hwnd )))
337 if (ptr != WND_OTHER_PROCESS)
339 /* increment destruction monitoring */
340 ptr->irefCount++;
341 return ptr;
343 if (IsWindow( hwnd )) /* check other processes */
345 ERR( "window %p belongs to other process\n", hwnd );
346 /* DbgBreakPoint(); */
349 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
350 return NULL;
354 /***********************************************************************
355 * WIN_ReleaseWndPtr
357 * Release the pointer to the WND structure.
359 void WIN_ReleaseWndPtr(WND *wndPtr)
361 if(!wndPtr) return;
363 /* Decrement destruction monitoring value */
364 wndPtr->irefCount--;
365 /* Check if it's time to release the memory */
366 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
368 /* Release memory */
369 free_window_handle( wndPtr->hwndSelf );
371 else if(wndPtr->irefCount < 0)
373 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
374 ERR("forgot a Lock on %p somewhere\n",wndPtr);
376 /* unlock all WND structures for thread safeness */
377 USER_Unlock();
381 /***********************************************************************
382 * WIN_UnlinkWindow
384 * Remove a window from the siblings linked list.
386 void WIN_UnlinkWindow( HWND hwnd )
388 WIN_LinkWindow( hwnd, 0, 0 );
392 /***********************************************************************
393 * WIN_LinkWindow
395 * Insert a window into the siblings linked list.
396 * The window is inserted after the specified window, which can also
397 * be specified as HWND_TOP or HWND_BOTTOM.
398 * If parent is 0, window is unlinked from the tree.
400 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
402 WND *wndPtr = WIN_GetPtr( hwnd );
404 if (!wndPtr) return;
405 if (wndPtr == WND_OTHER_PROCESS)
407 if (IsWindow(hwnd)) ERR(" cannot link other process window %p\n", hwnd );
408 return;
411 SERVER_START_REQ( link_window )
413 req->handle = hwnd;
414 req->parent = parent;
415 req->previous = hwndInsertAfter;
416 if (!wine_server_call( req ))
418 if (reply->full_parent) wndPtr->parent = reply->full_parent;
422 SERVER_END_REQ;
423 WIN_ReleasePtr( wndPtr );
427 /***********************************************************************
428 * WIN_SetOwner
430 * Change the owner of a window.
432 HWND WIN_SetOwner( HWND hwnd, HWND owner )
434 WND *win = WIN_GetPtr( hwnd );
435 HWND ret = 0;
437 if (!win) return 0;
438 if (win == WND_OTHER_PROCESS)
440 if (IsWindow(hwnd)) ERR( "cannot set owner %p on other process window %p\n", owner, hwnd );
441 return 0;
443 SERVER_START_REQ( set_window_owner )
445 req->handle = hwnd;
446 req->owner = owner;
447 if (!wine_server_call( req ))
449 win->owner = reply->full_owner;
450 ret = reply->prev_owner;
453 SERVER_END_REQ;
454 WIN_ReleasePtr( win );
455 return ret;
459 /***********************************************************************
460 * WIN_SetStyle
462 * Change the style of a window.
464 LONG WIN_SetStyle( HWND hwnd, LONG style )
466 BOOL ok;
467 LONG ret = 0;
468 WND *win = WIN_GetPtr( hwnd );
470 if (!win) return 0;
471 if (win == WND_OTHER_PROCESS)
473 if (IsWindow(hwnd))
474 ERR( "cannot set style %lx on other process window %p\n", style, hwnd );
475 return 0;
477 if (style == win->dwStyle)
479 WIN_ReleasePtr( win );
480 return style;
482 SERVER_START_REQ( set_window_info )
484 req->handle = hwnd;
485 req->flags = SET_WIN_STYLE;
486 req->style = style;
487 req->extra_offset = -1;
488 if ((ok = !wine_server_call( req )))
490 ret = reply->old_style;
491 win->dwStyle = style;
494 SERVER_END_REQ;
495 WIN_ReleasePtr( win );
496 if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
497 return ret;
501 /***********************************************************************
502 * WIN_SetExStyle
504 * Change the extended style of a window.
506 LONG WIN_SetExStyle( HWND hwnd, LONG style )
508 LONG ret = 0;
509 WND *win = WIN_GetPtr( hwnd );
511 if (!win) return 0;
512 if (win == WND_OTHER_PROCESS)
514 if (IsWindow(hwnd))
515 ERR( "cannot set exstyle %lx on other process window %p\n", style, hwnd );
516 return 0;
518 if (style == win->dwExStyle)
520 WIN_ReleasePtr( win );
521 return style;
523 SERVER_START_REQ( set_window_info )
525 req->handle = hwnd;
526 req->flags = SET_WIN_EXSTYLE;
527 req->ex_style = style;
528 req->extra_offset = -1;
529 if (!wine_server_call( req ))
531 ret = reply->old_ex_style;
532 win->dwExStyle = style;
535 SERVER_END_REQ;
536 WIN_ReleasePtr( win );
537 return ret;
541 /***********************************************************************
542 * WIN_SetRectangles
544 * Set the window and client rectangles.
546 void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient )
548 WND *win = WIN_GetPtr( hwnd );
549 BOOL ret;
551 if (!win) return;
552 if (win == WND_OTHER_PROCESS)
554 if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %p\n", hwnd );
555 return;
557 SERVER_START_REQ( set_window_rectangles )
559 req->handle = hwnd;
560 req->window.left = rectWindow->left;
561 req->window.top = rectWindow->top;
562 req->window.right = rectWindow->right;
563 req->window.bottom = rectWindow->bottom;
564 req->client.left = rectClient->left;
565 req->client.top = rectClient->top;
566 req->client.right = rectClient->right;
567 req->client.bottom = rectClient->bottom;
568 ret = !wine_server_call( req );
570 SERVER_END_REQ;
571 if (ret)
573 win->rectWindow = *rectWindow;
574 win->rectClient = *rectClient;
576 TRACE( "win %p window (%ld,%ld)-(%ld,%ld) client (%ld,%ld)-(%ld,%ld)\n", hwnd,
577 rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom,
578 rectClient->left, rectClient->top, rectClient->right, rectClient->bottom );
580 WIN_ReleasePtr( win );
584 /***********************************************************************
585 * WIN_GetRectangles
587 * Get the window and client rectangles.
589 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
591 WND *win = WIN_GetPtr( hwnd );
592 BOOL ret = TRUE;
594 if (!win) return FALSE;
595 if (win == WND_OTHER_PROCESS)
597 SERVER_START_REQ( get_window_rectangles )
599 req->handle = hwnd;
600 if ((ret = !wine_server_call( req )))
602 if (rectWindow)
604 rectWindow->left = reply->window.left;
605 rectWindow->top = reply->window.top;
606 rectWindow->right = reply->window.right;
607 rectWindow->bottom = reply->window.bottom;
609 if (rectClient)
611 rectClient->left = reply->client.left;
612 rectClient->top = reply->client.top;
613 rectClient->right = reply->client.right;
614 rectClient->bottom = reply->client.bottom;
618 SERVER_END_REQ;
620 else
622 if (rectWindow) *rectWindow = win->rectWindow;
623 if (rectClient) *rectClient = win->rectClient;
624 WIN_ReleasePtr( win );
626 return ret;
630 /***********************************************************************
631 * WIN_DestroyWindow
633 * Destroy storage associated to a window. "Internals" p.358
635 LRESULT WIN_DestroyWindow( HWND hwnd )
637 WND *wndPtr;
638 HWND *list;
640 TRACE("%p\n", hwnd );
642 if (!(hwnd = WIN_IsCurrentThread( hwnd )))
644 ERR( "window doesn't belong to current thread\n" );
645 return 0;
648 /* free child windows */
649 if ((list = WIN_ListChildren( hwnd )))
651 int i;
652 for (i = 0; list[i]; i++)
654 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
655 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
657 HeapFree( GetProcessHeap(), 0, list );
661 * Clear the update region to make sure no WM_PAINT messages will be
662 * generated for this window while processing the WM_NCDESTROY.
664 RedrawWindow( hwnd, NULL, 0,
665 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
668 * Send the WM_NCDESTROY to the window being destroyed.
670 SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
672 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
674 WINPOS_CheckInternalPos( hwnd );
675 if( hwnd == GetCapture()) ReleaseCapture();
677 /* free resources associated with the window */
679 TIMER_RemoveWindowTimers( hwnd );
681 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
683 if (!(wndPtr->dwStyle & WS_CHILD))
685 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
686 if (menu) DestroyMenu( menu );
688 if (wndPtr->hSysMenu)
690 DestroyMenu( wndPtr->hSysMenu );
691 wndPtr->hSysMenu = 0;
693 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
694 USER_Driver.pDestroyWindow( hwnd );
695 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
696 wndPtr->class = NULL;
697 wndPtr->dwMagic = 0; /* Mark it as invalid */
698 WIN_ReleaseWndPtr( wndPtr );
699 return 0;
702 /***********************************************************************
703 * WIN_DestroyThreadWindows
705 * Destroy all children of 'wnd' owned by the current thread.
706 * Return TRUE if something was done.
708 void WIN_DestroyThreadWindows( HWND hwnd )
710 HWND *list;
711 int i;
713 if (!(list = WIN_ListChildren( hwnd ))) return;
714 for (i = 0; list[i]; i++)
716 if (WIN_IsCurrentThread( list[i] ))
717 DestroyWindow( list[i] );
718 else
719 WIN_DestroyThreadWindows( list[i] );
721 HeapFree( GetProcessHeap(), 0, list );
724 /***********************************************************************
725 * WIN_CreateDesktopWindow
727 * Create the desktop window.
729 BOOL WIN_CreateDesktopWindow(void)
731 HWND hwndDesktop;
732 CREATESTRUCTA cs;
733 RECT rect;
735 TRACE("Creating desktop window\n");
737 if (!WINPOS_CreateInternalPosAtom()) return FALSE;
739 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W );
740 if (!pWndDesktop) return FALSE;
741 hwndDesktop = pWndDesktop->hwndSelf;
743 pWndDesktop->tid = 0; /* nobody owns the desktop */
744 pWndDesktop->parent = 0;
745 pWndDesktop->owner = 0;
746 pWndDesktop->text = NULL;
747 pWndDesktop->hrgnUpdate = 0;
748 pWndDesktop->pVScroll = NULL;
749 pWndDesktop->pHScroll = NULL;
750 pWndDesktop->helpContext = 0;
751 pWndDesktop->flags = 0;
752 pWndDesktop->hSysMenu = 0;
754 cs.lpCreateParams = NULL;
755 cs.hInstance = 0;
756 cs.hMenu = 0;
757 cs.hwndParent = 0;
758 cs.x = 0;
759 cs.y = 0;
760 cs.cx = GetSystemMetrics( SM_CXSCREEN );
761 cs.cy = GetSystemMetrics( SM_CYSCREEN );
762 cs.style = pWndDesktop->dwStyle;
763 cs.dwExStyle = pWndDesktop->dwExStyle;
764 cs.lpszName = NULL;
765 cs.lpszClass = DESKTOP_CLASS_ATOM;
767 SetRect( &rect, 0, 0, cs.cx, cs.cy );
768 WIN_SetRectangles( hwndDesktop, &rect, &rect );
770 SERVER_START_REQ( set_window_info )
772 req->handle = hwndDesktop;
773 req->flags = 0; /* don't set anything, just retrieve */
774 req->extra_offset = -1;
775 wine_server_call( req );
776 pWndDesktop->dwStyle = reply->old_style;
777 pWndDesktop->dwExStyle = reply->old_ex_style;
778 pWndDesktop->hInstance = (HINSTANCE)reply->old_instance;
779 pWndDesktop->userdata = (ULONG_PTR)reply->old_user_data;
780 pWndDesktop->wIDmenu = reply->old_id;
782 SERVER_END_REQ;
784 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
786 WIN_ReleaseWndPtr( pWndDesktop );
787 return FALSE;
790 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
791 WIN_ReleaseWndPtr( pWndDesktop );
792 return TRUE;
796 /***********************************************************************
797 * WIN_FixCoordinates
799 * Fix the coordinates - Helper for WIN_CreateWindowEx.
800 * returns default show mode in sw.
801 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
803 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
805 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
806 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
808 if (cs->style & (WS_CHILD | WS_POPUP))
810 if (cs->dwExStyle & WS_EX_MDICHILD)
812 POINT pos[2];
814 MDI_CalcDefaultChildPos(cs->hwndParent, -1, pos, 0);
816 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
818 cs->x = pos[0].x;
819 cs->y = pos[0].y;
821 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16 || !cs->cx)
822 cs->cx = pos[1].x;
823 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16 || !cs->cy)
824 cs->cy = pos[1].y;
826 else
828 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
829 cs->x = cs->y = 0;
830 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
831 cs->cx = cs->cy = 0;
834 else /* overlapped window */
836 STARTUPINFOA info;
838 GetStartupInfoA( &info );
840 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
842 /* Never believe Microsoft's documentation... CreateWindowEx doc says
843 * that if an overlapped window is created with WS_VISIBLE style bit
844 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
845 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
846 * reveals that
848 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
849 * 2) it does not ignore the y parameter as the docs claim; instead, it
850 * uses it as second parameter to ShowWindow() unless y is either
851 * CW_USEDEFAULT or CW_USEDEFAULT16.
853 * The fact that we didn't do 2) caused bogus windows pop up when wine
854 * was running apps that were using this obscure feature. Example -
855 * calc.exe that comes with Win98 (only Win98, it's different from
856 * the one that comes with Win95 and NT)
858 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
859 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
860 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
863 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
865 if (info.dwFlags & STARTF_USESIZE)
867 cs->cx = info.dwXSize;
868 cs->cy = info.dwYSize;
870 else /* if no other hint from the app, pick 3/4 of the screen real estate */
872 RECT r;
873 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
874 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
875 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
880 else
882 /* neither x nor cx are default. Check the y values .
883 * In the trace we see Outlook and Outlook Express using
884 * cy set to CW_USEDEFAULT when opening the address book.
886 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
887 RECT r;
888 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
889 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
890 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
895 /***********************************************************************
896 * dump_window_styles
898 static void dump_window_styles( DWORD style, DWORD exstyle )
900 TRACE( "style:" );
901 if(style & WS_POPUP) TRACE(" WS_POPUP");
902 if(style & WS_CHILD) TRACE(" WS_CHILD");
903 if(style & WS_MINIMIZE) TRACE(" WS_MINIMIZE");
904 if(style & WS_VISIBLE) TRACE(" WS_VISIBLE");
905 if(style & WS_DISABLED) TRACE(" WS_DISABLED");
906 if(style & WS_CLIPSIBLINGS) TRACE(" WS_CLIPSIBLINGS");
907 if(style & WS_CLIPCHILDREN) TRACE(" WS_CLIPCHILDREN");
908 if(style & WS_MAXIMIZE) TRACE(" WS_MAXIMIZE");
909 if((style & WS_CAPTION) == WS_CAPTION) TRACE(" WS_CAPTION");
910 else
912 if(style & WS_BORDER) TRACE(" WS_BORDER");
913 if(style & WS_DLGFRAME) TRACE(" WS_DLGFRAME");
915 if(style & WS_VSCROLL) TRACE(" WS_VSCROLL");
916 if(style & WS_HSCROLL) TRACE(" WS_HSCROLL");
917 if(style & WS_SYSMENU) TRACE(" WS_SYSMENU");
918 if(style & WS_THICKFRAME) TRACE(" WS_THICKFRAME");
919 if(style & WS_GROUP) TRACE(" WS_GROUP");
920 if(style & WS_TABSTOP) TRACE(" WS_TABSTOP");
921 if(style & WS_MINIMIZEBOX) TRACE(" WS_MINIMIZEBOX");
922 if(style & WS_MAXIMIZEBOX) TRACE(" WS_MAXIMIZEBOX");
924 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
925 #define DUMPED_STYLES \
926 (WS_POPUP | \
927 WS_CHILD | \
928 WS_MINIMIZE | \
929 WS_VISIBLE | \
930 WS_DISABLED | \
931 WS_CLIPSIBLINGS | \
932 WS_CLIPCHILDREN | \
933 WS_MAXIMIZE | \
934 WS_BORDER | \
935 WS_DLGFRAME | \
936 WS_VSCROLL | \
937 WS_HSCROLL | \
938 WS_SYSMENU | \
939 WS_THICKFRAME | \
940 WS_GROUP | \
941 WS_TABSTOP | \
942 WS_MINIMIZEBOX | \
943 WS_MAXIMIZEBOX)
945 if(style & ~DUMPED_STYLES) TRACE(" %08lx", style & ~DUMPED_STYLES);
946 TRACE("\n");
947 #undef DUMPED_STYLES
949 TRACE( "exstyle:" );
950 if(exstyle & WS_EX_DLGMODALFRAME) TRACE(" WS_EX_DLGMODALFRAME");
951 if(exstyle & WS_EX_DRAGDETECT) TRACE(" WS_EX_DRAGDETECT");
952 if(exstyle & WS_EX_NOPARENTNOTIFY) TRACE(" WS_EX_NOPARENTNOTIFY");
953 if(exstyle & WS_EX_TOPMOST) TRACE(" WS_EX_TOPMOST");
954 if(exstyle & WS_EX_ACCEPTFILES) TRACE(" WS_EX_ACCEPTFILES");
955 if(exstyle & WS_EX_TRANSPARENT) TRACE(" WS_EX_TRANSPARENT");
956 if(exstyle & WS_EX_MDICHILD) TRACE(" WS_EX_MDICHILD");
957 if(exstyle & WS_EX_TOOLWINDOW) TRACE(" WS_EX_TOOLWINDOW");
958 if(exstyle & WS_EX_WINDOWEDGE) TRACE(" WS_EX_WINDOWEDGE");
959 if(exstyle & WS_EX_CLIENTEDGE) TRACE(" WS_EX_CLIENTEDGE");
960 if(exstyle & WS_EX_CONTEXTHELP) TRACE(" WS_EX_CONTEXTHELP");
961 if(exstyle & WS_EX_RIGHT) TRACE(" WS_EX_RIGHT");
962 if(exstyle & WS_EX_RTLREADING) TRACE(" WS_EX_RTLREADING");
963 if(exstyle & WS_EX_LEFTSCROLLBAR) TRACE(" WS_EX_LEFTSCROLLBAR");
964 if(exstyle & WS_EX_CONTROLPARENT) TRACE(" WS_EX_CONTROLPARENT");
965 if(exstyle & WS_EX_STATICEDGE) TRACE(" WS_EX_STATICEDGE");
966 if(exstyle & WS_EX_APPWINDOW) TRACE(" WS_EX_APPWINDOW");
967 if(exstyle & WS_EX_LAYERED) TRACE(" WS_EX_LAYERED");
969 #define DUMPED_EX_STYLES \
970 (WS_EX_DLGMODALFRAME | \
971 WS_EX_DRAGDETECT | \
972 WS_EX_NOPARENTNOTIFY | \
973 WS_EX_TOPMOST | \
974 WS_EX_ACCEPTFILES | \
975 WS_EX_TRANSPARENT | \
976 WS_EX_MDICHILD | \
977 WS_EX_TOOLWINDOW | \
978 WS_EX_WINDOWEDGE | \
979 WS_EX_CLIENTEDGE | \
980 WS_EX_CONTEXTHELP | \
981 WS_EX_RIGHT | \
982 WS_EX_RTLREADING | \
983 WS_EX_LEFTSCROLLBAR | \
984 WS_EX_CONTROLPARENT | \
985 WS_EX_STATICEDGE | \
986 WS_EX_APPWINDOW | \
987 WS_EX_LAYERED)
989 if(exstyle & ~DUMPED_EX_STYLES) TRACE(" %08lx", exstyle & ~DUMPED_EX_STYLES);
990 TRACE("\n");
991 #undef DUMPED_EX_STYLES
995 /***********************************************************************
996 * WIN_CreateWindowEx
998 * Implementation of CreateWindowEx().
1000 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
1001 WINDOWPROCTYPE type )
1003 INT sw = SW_SHOW;
1004 WND *wndPtr;
1005 HWND hwnd, parent, owner, top_child = 0;
1006 BOOL unicode = (type == WIN_PROC_32W);
1008 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%p menu=%p inst=%p params=%p\n",
1009 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1010 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
1011 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1012 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1014 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1016 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1017 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1019 /* Fix the styles for MDI children */
1020 if (cs->dwExStyle & WS_EX_MDICHILD)
1022 MDICREATESTRUCTA mdi_cs;
1023 UINT flags = 0;
1025 wndPtr = WIN_GetPtr(cs->hwndParent);
1026 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
1028 flags = wndPtr->flags;
1029 WIN_ReleasePtr(wndPtr);
1032 if (!(flags & WIN_ISMDICLIENT))
1034 WARN("WS_EX_MDICHILD, but parent %p is not MDIClient\n", cs->hwndParent);
1035 return 0;
1038 /* cs->lpCreateParams of WM_[NC]CREATE is different for MDI children.
1039 * MDICREATESTRUCT members have the originally passed values.
1041 * Note: we rely on the fact that MDICREATESTRUCTA and MDICREATESTRUCTW
1042 * have the same layout.
1044 mdi_cs.szClass = cs->lpszClass;
1045 mdi_cs.szTitle = cs->lpszName;
1046 mdi_cs.hOwner = cs->hInstance;
1047 mdi_cs.x = cs->x;
1048 mdi_cs.y = cs->y;
1049 mdi_cs.cx = cs->cx;
1050 mdi_cs.cy = cs->cy;
1051 mdi_cs.style = cs->style;
1052 mdi_cs.lParam = (LPARAM)cs->lpCreateParams;
1054 cs->lpCreateParams = (LPVOID)&mdi_cs;
1056 if (GetWindowLongW(cs->hwndParent, GWL_STYLE) & MDIS_ALLCHILDSTYLES)
1058 if (cs->style & WS_POPUP)
1060 TRACE("WS_POPUP with MDIS_ALLCHILDSTYLES is not allowed\n");
1061 return 0;
1063 cs->style |= WS_CHILD | WS_CLIPSIBLINGS;
1065 else
1067 cs->style &= ~WS_POPUP;
1068 cs->style |= WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CAPTION |
1069 WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
1072 top_child = GetWindow(cs->hwndParent, GW_CHILD);
1075 /* Find the parent window */
1077 parent = GetDesktopWindow();
1078 owner = 0;
1080 if (cs->hwndParent == HWND_MESSAGE)
1082 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
1083 * message window (style: WS_POPUP|WS_DISABLED)
1085 FIXME("Parent is HWND_MESSAGE\n");
1087 else if (cs->hwndParent)
1089 /* Make sure parent is valid */
1090 if (!IsWindow( cs->hwndParent ))
1092 WARN("Bad parent %p\n", cs->hwndParent );
1093 return 0;
1095 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1096 parent = WIN_GetFullHandle(cs->hwndParent);
1097 else
1098 owner = GetAncestor( cs->hwndParent, GA_ROOT );
1100 else if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1102 WARN("No parent for child window\n" );
1103 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1106 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1108 /* Correct the window styles.
1110 * It affects both the style loaded into the WIN structure and
1111 * passed in the CREATESTRUCT to the WM_[NC]CREATE.
1113 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1114 * why does the user get to set it?
1117 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1118 * tested for WS_POPUP
1120 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1121 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1122 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1123 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1124 else
1125 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1127 if (!(cs->style & WS_CHILD))
1129 cs->style |= WS_CLIPSIBLINGS;
1130 if (!(cs->style & WS_POPUP))
1131 cs->style |= WS_CAPTION;
1134 /* Create the window structure */
1136 if (!(wndPtr = create_window_handle( parent, owner, classAtom, cs->hInstance, type )))
1138 TRACE("out of memory\n" );
1139 return 0;
1141 hwnd = wndPtr->hwndSelf;
1143 /* Fill the window structure */
1145 wndPtr->tid = GetCurrentThreadId();
1146 wndPtr->owner = owner;
1147 wndPtr->parent = parent;
1148 wndPtr->hInstance = cs->hInstance;
1149 wndPtr->text = NULL;
1150 wndPtr->hrgnUpdate = 0;
1151 wndPtr->hrgnWnd = 0;
1152 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1153 wndPtr->dwExStyle = cs->dwExStyle;
1154 wndPtr->wIDmenu = 0;
1155 wndPtr->helpContext = 0;
1156 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1157 wndPtr->pVScroll = NULL;
1158 wndPtr->pHScroll = NULL;
1159 wndPtr->userdata = 0;
1160 wndPtr->hIcon = 0;
1161 wndPtr->hIconSmall = 0;
1162 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU) ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1164 if (!(cs->style & (WS_CHILD | WS_POPUP)))
1165 wndPtr->flags |= WIN_NEED_SIZE;
1167 SERVER_START_REQ( set_window_info )
1169 req->handle = hwnd;
1170 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1171 req->style = wndPtr->dwStyle;
1172 req->ex_style = wndPtr->dwExStyle;
1173 req->instance = (void *)wndPtr->hInstance;
1174 req->extra_offset = -1;
1175 wine_server_call( req );
1177 SERVER_END_REQ;
1179 /* Get class or window DC if needed */
1181 if (wndPtr->clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1183 /* Set the window menu */
1185 if (((wndPtr->dwStyle & (WS_CAPTION|WS_CHILD)) == WS_CAPTION) ||
1186 (wndPtr->dwExStyle & WS_EX_APPWINDOW))
1188 if (cs->hMenu) MENU_SetMenu(hwnd, cs->hMenu);
1189 else
1191 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1192 if (menuName)
1194 if (HIWORD(cs->hInstance))
1195 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1196 else
1197 cs->hMenu = HMENU_32(LoadMenu16(HINSTANCE_16(cs->hInstance),menuName));
1199 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1203 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1204 WIN_ReleaseWndPtr( wndPtr );
1206 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1208 WIN_DestroyWindow( hwnd );
1209 return 0;
1212 /* Notify the parent window only */
1214 send_parent_notify( hwnd, WM_CREATE );
1215 if (!IsWindow( hwnd )) return 0;
1217 if (cs->dwExStyle & WS_EX_MDICHILD)
1219 if (top_child)
1221 /* Restore current maximized child */
1222 if((cs->style & WS_VISIBLE) && IsZoomed(top_child))
1224 TRACE("Restoring current maximized child %p\n", top_child);
1225 ShowWindow(top_child, SW_SHOWNOACTIVATE);
1229 SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1232 if (cs->style & WS_VISIBLE)
1234 /* in case WS_VISIBLE got set in the meantime */
1235 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1236 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1237 WIN_ReleasePtr( wndPtr );
1238 ShowWindow( hwnd, sw );
1241 /* Call WH_SHELL hook */
1243 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1244 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1246 TRACE("created window %p\n", hwnd);
1247 return hwnd;
1251 /***********************************************************************
1252 * CreateWindow (USER.41)
1254 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1255 DWORD style, INT16 x, INT16 y, INT16 width,
1256 INT16 height, HWND16 parent, HMENU16 menu,
1257 HINSTANCE16 instance, LPVOID data )
1259 return CreateWindowEx16( 0, className, windowName, style,
1260 x, y, width, height, parent, menu, instance, data );
1264 /***********************************************************************
1265 * CreateWindowEx (USER.452)
1267 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1268 LPCSTR windowName, DWORD style, INT16 x,
1269 INT16 y, INT16 width, INT16 height,
1270 HWND16 parent, HMENU16 menu,
1271 HINSTANCE16 instance, LPVOID data )
1273 ATOM classAtom;
1274 CREATESTRUCTA cs;
1275 char buffer[256];
1277 /* Find the class atom */
1279 if (HIWORD(className))
1281 if (!(classAtom = GlobalFindAtomA( className )))
1283 ERR( "bad class name %s\n", debugstr_a(className) );
1284 return 0;
1287 else
1289 classAtom = LOWORD(className);
1290 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1292 ERR( "bad atom %x\n", classAtom);
1293 return 0;
1295 className = buffer;
1298 /* Fix the coordinates */
1300 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1301 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1302 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1303 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1305 /* Create the window */
1307 cs.lpCreateParams = data;
1308 cs.hInstance = HINSTANCE_32(instance);
1309 cs.hMenu = HMENU_32(menu);
1310 cs.hwndParent = WIN_Handle32( parent );
1311 cs.style = style;
1312 cs.lpszName = windowName;
1313 cs.lpszClass = className;
1314 cs.dwExStyle = exStyle;
1316 return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1320 /***********************************************************************
1321 * CreateWindowExA (USER32.@)
1323 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1324 LPCSTR windowName, DWORD style, INT x,
1325 INT y, INT width, INT height,
1326 HWND parent, HMENU menu,
1327 HINSTANCE instance, LPVOID data )
1329 ATOM classAtom;
1330 CREATESTRUCTA cs;
1331 char buffer[256];
1333 /* Find the class atom */
1335 if (HIWORD(className))
1337 if (!(classAtom = GlobalFindAtomA( className )))
1339 ERR( "bad class name %s\n", debugstr_a(className) );
1340 return 0;
1343 else
1345 classAtom = LOWORD(className);
1346 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1348 ERR( "bad atom %x\n", classAtom);
1349 return 0;
1351 className = buffer;
1354 /* Create the window */
1356 cs.lpCreateParams = data;
1357 cs.hInstance = instance;
1358 cs.hMenu = menu;
1359 cs.hwndParent = parent;
1360 cs.x = x;
1361 cs.y = y;
1362 cs.cx = width;
1363 cs.cy = height;
1364 cs.style = style;
1365 cs.lpszName = windowName;
1366 cs.lpszClass = className;
1367 cs.dwExStyle = exStyle;
1369 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1373 /***********************************************************************
1374 * CreateWindowExW (USER32.@)
1376 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1377 LPCWSTR windowName, DWORD style, INT x,
1378 INT y, INT width, INT height,
1379 HWND parent, HMENU menu,
1380 HINSTANCE instance, LPVOID data )
1382 ATOM classAtom;
1383 CREATESTRUCTW cs;
1384 WCHAR buffer[256];
1386 /* Find the class atom */
1388 if (HIWORD(className))
1390 if (!(classAtom = GlobalFindAtomW( className )))
1392 ERR( "bad class name %s\n", debugstr_w(className) );
1393 return 0;
1396 else
1398 classAtom = LOWORD(className);
1399 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1401 ERR( "bad atom %x\n", classAtom);
1402 return 0;
1404 className = buffer;
1407 /* Create the window */
1409 cs.lpCreateParams = data;
1410 cs.hInstance = instance;
1411 cs.hMenu = menu;
1412 cs.hwndParent = parent;
1413 cs.x = x;
1414 cs.y = y;
1415 cs.cx = width;
1416 cs.cy = height;
1417 cs.style = style;
1418 cs.lpszName = windowName;
1419 cs.lpszClass = className;
1420 cs.dwExStyle = exStyle;
1422 /* Note: we rely on the fact that CREATESTRUCTA and */
1423 /* CREATESTRUCTW have the same layout. */
1424 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1428 /***********************************************************************
1429 * WIN_SendDestroyMsg
1431 static void WIN_SendDestroyMsg( HWND hwnd )
1433 GUITHREADINFO info;
1435 if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1437 if (hwnd == info.hwndCaret) DestroyCaret();
1439 if (USER_Driver.pResetSelectionOwner)
1440 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1443 * Send the WM_DESTROY to the window.
1445 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1448 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1449 * make sure that the window still exists when we come back.
1451 if (IsWindow(hwnd))
1453 HWND* pWndArray;
1454 int i;
1456 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1458 /* start from the end (FIXME: is this needed?) */
1459 for (i = 0; pWndArray[i]; i++) ;
1461 while (--i >= 0)
1463 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1465 HeapFree( GetProcessHeap(), 0, pWndArray );
1467 else
1468 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1472 /***********************************************************************
1473 * DestroyWindow (USER32.@)
1475 BOOL WINAPI DestroyWindow( HWND hwnd )
1477 BOOL is_child;
1479 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1481 SetLastError( ERROR_ACCESS_DENIED );
1482 return FALSE;
1485 TRACE("(%p)\n", hwnd);
1487 if (GetWindowLongW(hwnd, GWL_EXSTYLE) & WS_EX_MDICHILD)
1488 SendMessageW(GetAncestor(hwnd, GA_PARENT), WM_MDIREFRESHMENU, 0, 0);
1490 /* Call hooks */
1492 if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1494 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1496 if (is_child)
1498 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1499 send_parent_notify( hwnd, WM_DESTROY );
1501 else if (!GetWindow( hwnd, GW_OWNER ))
1503 HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1504 /* FIXME: clean up palette - see "Internals" p.352 */
1507 if (!IsWindow(hwnd)) return TRUE;
1509 if (USER_Driver.pResetSelectionOwner)
1510 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1512 /* Hide the window */
1514 if (!ShowWindow( hwnd, SW_HIDE ))
1516 if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd );
1518 if (!IsWindow(hwnd)) return TRUE;
1520 /* Recursively destroy owned windows */
1522 if (!is_child)
1524 for (;;)
1526 int i, got_one = 0;
1527 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1528 if (list)
1530 for (i = 0; list[i]; i++)
1532 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1533 if (WIN_IsCurrentThread( list[i] ))
1535 DestroyWindow( list[i] );
1536 got_one = 1;
1537 continue;
1539 WIN_SetOwner( list[i], 0 );
1541 HeapFree( GetProcessHeap(), 0, list );
1543 if (!got_one) break;
1547 /* Send destroy messages */
1549 WIN_SendDestroyMsg( hwnd );
1550 if (!IsWindow( hwnd )) return TRUE;
1552 if (GetClipboardOwner() == hwnd)
1553 CLIPBOARD_ReleaseOwner();
1555 /* Unlink now so we won't bother with the children later on */
1557 WIN_UnlinkWindow( hwnd );
1559 /* Destroy the window storage */
1561 WIN_DestroyWindow( hwnd );
1562 return TRUE;
1566 /***********************************************************************
1567 * CloseWindow (USER32.@)
1569 BOOL WINAPI CloseWindow( HWND hwnd )
1571 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1572 ShowWindow( hwnd, SW_MINIMIZE );
1573 return TRUE;
1577 /***********************************************************************
1578 * OpenIcon (USER32.@)
1580 BOOL WINAPI OpenIcon( HWND hwnd )
1582 if (!IsIconic( hwnd )) return FALSE;
1583 ShowWindow( hwnd, SW_SHOWNORMAL );
1584 return TRUE;
1588 /***********************************************************************
1589 * WIN_FindWindow
1591 * Implementation of FindWindow() and FindWindowEx().
1593 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1595 HWND *list = NULL;
1596 HWND retvalue = 0;
1597 int i = 0, len = 0;
1598 WCHAR *buffer = NULL;
1600 if (!parent) parent = GetDesktopWindow();
1601 if (title)
1603 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1604 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1607 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1609 if (child)
1611 child = WIN_GetFullHandle( child );
1612 while (list[i] && list[i] != child) i++;
1613 if (!list[i]) goto done;
1614 i++; /* start from next window */
1617 if (title)
1619 while (list[i])
1621 if (GetWindowTextW( list[i], buffer, len + 1 ) && !strcmpiW( buffer, title )) break;
1622 i++;
1625 retvalue = list[i];
1627 done:
1628 if (list) HeapFree( GetProcessHeap(), 0, list );
1629 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1630 return retvalue;
1635 /***********************************************************************
1636 * FindWindowA (USER32.@)
1638 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1640 HWND ret = FindWindowExA( 0, 0, className, title );
1641 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1642 return ret;
1646 /***********************************************************************
1647 * FindWindowExA (USER32.@)
1649 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1650 LPCSTR className, LPCSTR title )
1652 ATOM atom = 0;
1653 LPWSTR buffer;
1654 HWND hwnd;
1655 INT len;
1657 if (className)
1659 /* If the atom doesn't exist, then no class */
1660 /* with this name exists either. */
1661 if (!(atom = GlobalFindAtomA( className )))
1663 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1664 return 0;
1667 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1669 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1670 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1671 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1672 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1673 HeapFree( GetProcessHeap(), 0, buffer );
1674 return hwnd;
1678 /***********************************************************************
1679 * FindWindowExW (USER32.@)
1681 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1682 LPCWSTR className, LPCWSTR title )
1684 ATOM atom = 0;
1686 if (className)
1688 /* If the atom doesn't exist, then no class */
1689 /* with this name exists either. */
1690 if (!(atom = GlobalFindAtomW( className )))
1692 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1693 return 0;
1696 return WIN_FindWindow( parent, child, atom, title );
1700 /***********************************************************************
1701 * FindWindowW (USER32.@)
1703 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1705 return FindWindowExW( 0, 0, className, title );
1709 /**********************************************************************
1710 * GetDesktopWindow (USER32.@)
1712 HWND WINAPI GetDesktopWindow(void)
1714 if (pWndDesktop) return pWndDesktop->hwndSelf;
1715 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" );
1716 ExitProcess(1);
1717 return 0;
1721 /*******************************************************************
1722 * EnableWindow (USER32.@)
1724 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1726 WND *wndPtr;
1727 BOOL retvalue;
1728 LONG style;
1729 HWND full_handle;
1731 if (is_broadcast(hwnd))
1733 SetLastError( ERROR_INVALID_PARAMETER );
1734 return FALSE;
1737 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1738 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1740 hwnd = full_handle;
1742 TRACE("( %p, %d )\n", hwnd, enable);
1744 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1745 style = wndPtr->dwStyle;
1746 retvalue = ((style & WS_DISABLED) != 0);
1747 WIN_ReleasePtr( wndPtr );
1749 if (enable && retvalue)
1751 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1752 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1754 else if (!enable && !retvalue)
1756 HWND focus_wnd, capture_wnd;
1758 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1760 WIN_SetStyle( hwnd, style | WS_DISABLED );
1762 focus_wnd = GetFocus();
1763 if (hwnd == focus_wnd || IsChild(hwnd, focus_wnd))
1764 SetFocus( 0 ); /* A disabled window can't have the focus */
1766 capture_wnd = GetCapture();
1767 if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1768 ReleaseCapture(); /* A disabled window can't capture the mouse */
1770 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1772 return retvalue;
1776 /***********************************************************************
1777 * IsWindowEnabled (USER32.@)
1779 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1781 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1785 /***********************************************************************
1786 * IsWindowUnicode (USER32.@)
1788 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1790 WND * wndPtr;
1791 BOOL retvalue;
1793 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1794 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1795 WIN_ReleaseWndPtr(wndPtr);
1796 return retvalue;
1800 /**********************************************************************
1801 * GetWindowWord (USER32.@)
1803 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1805 if (offset >= 0)
1807 WORD retvalue = 0;
1808 WND *wndPtr = WIN_GetPtr( hwnd );
1809 if (!wndPtr)
1811 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1812 return 0;
1814 if (wndPtr == WND_OTHER_PROCESS)
1816 SERVER_START_REQ( set_window_info )
1818 req->handle = hwnd;
1819 req->flags = 0; /* don't set anything, just retrieve */
1820 req->extra_offset = offset;
1821 req->extra_size = sizeof(retvalue);
1822 if (!wine_server_call_err( req ))
1823 memcpy( &retvalue, &reply->old_extra_value, sizeof(retvalue) );
1825 SERVER_END_REQ;
1826 return retvalue;
1828 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1830 WARN("Invalid offset %d\n", offset );
1831 SetLastError( ERROR_INVALID_INDEX );
1833 else memcpy( &retvalue, (char *)wndPtr->wExtra + offset, sizeof(retvalue) );
1834 WIN_ReleasePtr( wndPtr );
1835 return retvalue;
1838 switch(offset)
1840 case GWL_HWNDPARENT:
1841 return GetWindowLongW( hwnd, offset );
1842 case GWL_ID:
1843 case GWL_HINSTANCE:
1845 LONG ret = GetWindowLongW( hwnd, offset );
1846 if (HIWORD(ret))
1847 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1848 return LOWORD(ret);
1850 default:
1851 WARN("Invalid offset %d\n", offset );
1852 return 0;
1857 /**********************************************************************
1858 * SetWindowWord (USER32.@)
1860 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1862 WORD retval = 0;
1863 WND * wndPtr;
1865 switch(offset)
1867 case GWL_ID:
1868 case GWL_HINSTANCE:
1869 case GWL_HWNDPARENT:
1870 return SetWindowLongW( hwnd, offset, (UINT)newval );
1871 default:
1872 if (offset < 0)
1874 WARN("Invalid offset %d\n", offset );
1875 SetLastError( ERROR_INVALID_INDEX );
1876 return 0;
1880 wndPtr = WIN_GetPtr( hwnd );
1881 if (wndPtr == WND_OTHER_PROCESS)
1883 if (IsWindow(hwnd))
1884 FIXME( "set %d <- %x not supported yet on other process window %p\n",
1885 offset, newval, hwnd );
1886 wndPtr = NULL;
1888 if (!wndPtr)
1890 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1891 return 0;
1894 if (offset > (int)(wndPtr->cbWndExtra - sizeof(WORD)))
1896 WARN("Invalid offset %d\n", offset );
1897 WIN_ReleasePtr(wndPtr);
1898 SetLastError( ERROR_INVALID_INDEX );
1899 return 0;
1902 SERVER_START_REQ( set_window_info )
1904 req->handle = hwnd;
1905 req->flags = SET_WIN_EXTRA;
1906 req->extra_offset = offset;
1907 req->extra_size = sizeof(newval);
1908 memcpy( &req->extra_value, &newval, sizeof(newval) );
1909 if (!wine_server_call_err( req ))
1911 void *ptr = (char *)wndPtr->wExtra + offset;
1912 memcpy( &retval, ptr, sizeof(retval) );
1913 memcpy( ptr, &newval, sizeof(newval) );
1916 SERVER_END_REQ;
1917 WIN_ReleasePtr( wndPtr );
1918 return retval;
1922 /**********************************************************************
1923 * WIN_GetWindowLong
1925 * Helper function for GetWindowLong().
1927 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1929 LONG retvalue = 0;
1930 WND *wndPtr;
1932 if (offset == GWL_HWNDPARENT)
1934 HWND parent = GetAncestor( hwnd, GA_PARENT );
1935 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1936 return (LONG)parent;
1939 if (!(wndPtr = WIN_GetPtr( hwnd )))
1941 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1942 return 0;
1945 if (wndPtr == WND_OTHER_PROCESS)
1947 if (offset == GWL_WNDPROC)
1949 SetLastError( ERROR_ACCESS_DENIED );
1950 return 0;
1952 SERVER_START_REQ( set_window_info )
1954 req->handle = hwnd;
1955 req->flags = 0; /* don't set anything, just retrieve */
1956 req->extra_offset = (offset >= 0) ? offset : -1;
1957 req->extra_size = (offset >= 0) ? sizeof(retvalue) : 0;
1958 if (!wine_server_call_err( req ))
1960 switch(offset)
1962 case GWL_STYLE: retvalue = reply->old_style; break;
1963 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1964 case GWL_ID: retvalue = reply->old_id; break;
1965 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1966 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1967 default:
1968 if (offset >= 0) retvalue = reply->old_extra_value;
1969 else SetLastError( ERROR_INVALID_INDEX );
1970 break;
1974 SERVER_END_REQ;
1975 return retvalue;
1978 /* now we have a valid wndPtr */
1980 if (offset >= 0)
1982 if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
1985 * Some programs try to access last element from 16 bit
1986 * code using illegal offset value. Hopefully this is
1987 * what those programs really expect.
1989 if (type == WIN_PROC_16 &&
1990 wndPtr->cbWndExtra >= 4 &&
1991 offset == wndPtr->cbWndExtra - sizeof(WORD))
1993 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1995 ERR( "- replaced invalid offset %d with %d\n",
1996 offset, offset2 );
1998 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1999 WIN_ReleasePtr( wndPtr );
2000 return retvalue;
2002 WARN("Invalid offset %d\n", offset );
2003 WIN_ReleasePtr( wndPtr );
2004 SetLastError( ERROR_INVALID_INDEX );
2005 return 0;
2007 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
2008 /* Special case for dialog window procedure */
2009 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2010 retvalue = (LONG)WINPROC_GetProc( (WNDPROC)retvalue, type );
2011 WIN_ReleasePtr( wndPtr );
2012 return retvalue;
2015 switch(offset)
2017 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
2018 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
2019 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
2020 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
2021 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
2022 case GWL_HINSTANCE: retvalue = (LONG)wndPtr->hInstance; break;
2023 default:
2024 WARN("Unknown offset %d\n", offset );
2025 SetLastError( ERROR_INVALID_INDEX );
2026 break;
2028 WIN_ReleasePtr(wndPtr);
2029 return retvalue;
2033 /**********************************************************************
2034 * WIN_SetWindowLong
2036 * Helper function for SetWindowLong().
2038 * 0 is the failure code. However, in the case of failure SetLastError
2039 * must be set to distinguish between a 0 return value and a failure.
2041 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
2042 WINDOWPROCTYPE type )
2044 STYLESTRUCT style;
2045 BOOL ok;
2046 LONG retval = 0;
2047 WND *wndPtr;
2049 TRACE( "%p %d %lx %x\n", hwnd, offset, newval, type );
2051 if (is_broadcast(hwnd))
2053 SetLastError( ERROR_INVALID_PARAMETER );
2054 return FALSE;
2056 if (!WIN_IsCurrentProcess( hwnd ))
2058 if (offset == GWL_WNDPROC)
2060 SetLastError( ERROR_ACCESS_DENIED );
2061 return 0;
2063 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
2066 wndPtr = WIN_GetPtr( hwnd );
2067 if (wndPtr->hwndSelf == GetDesktopWindow())
2069 /* can't change anything on the desktop window */
2070 WIN_ReleasePtr( wndPtr );
2071 SetLastError( ERROR_ACCESS_DENIED );
2072 return 0;
2075 /* first some special cases */
2076 switch( offset )
2078 case GWL_STYLE:
2079 case GWL_EXSTYLE:
2080 style.styleOld =
2081 offset == GWL_STYLE ? wndPtr->dwStyle : wndPtr->dwExStyle;
2082 style.styleNew = newval;
2083 WIN_ReleasePtr( wndPtr );
2084 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2085 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2086 newval = style.styleNew;
2087 break;
2088 case GWL_HWNDPARENT:
2089 if (wndPtr->parent == GetDesktopWindow())
2091 WIN_ReleasePtr( wndPtr );
2092 return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
2094 else
2096 WIN_ReleasePtr( wndPtr );
2097 return (LONG)SetParent( hwnd, (HWND)newval );
2099 case GWL_WNDPROC:
2100 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2101 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2102 WIN_ReleasePtr( wndPtr );
2103 return retval;
2104 case GWL_ID:
2105 case GWL_HINSTANCE:
2106 case GWL_USERDATA:
2107 break;
2108 case DWL_DLGPROC:
2109 if ((wndPtr->cbWndExtra + sizeof(LONG) >= DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2111 WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWL_DLGPROC);
2112 retval = (LONG)WINPROC_GetProc( *ptr, type );
2113 WINPROC_SetProc( ptr, (WNDPROC)newval, type, WIN_PROC_WINDOW );
2114 WIN_ReleasePtr( wndPtr );
2115 return retval;
2117 /* fall through */
2118 default:
2119 if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2121 WARN("Invalid offset %d\n", offset );
2122 WIN_ReleasePtr( wndPtr );
2123 SetLastError( ERROR_INVALID_INDEX );
2124 return 0;
2126 else
2128 LONG *ptr = (LONG *)((char *)wndPtr->wExtra + offset);
2129 if (*ptr == newval) /* already set to the same value */
2131 WIN_ReleasePtr( wndPtr );
2132 return newval;
2135 break;
2138 SERVER_START_REQ( set_window_info )
2140 req->handle = hwnd;
2141 req->extra_offset = -1;
2142 switch(offset)
2144 case GWL_STYLE:
2145 req->flags = SET_WIN_STYLE;
2146 req->style = newval;
2147 break;
2148 case GWL_EXSTYLE:
2149 req->flags = SET_WIN_EXSTYLE;
2150 req->ex_style = newval;
2151 break;
2152 case GWL_ID:
2153 req->flags = SET_WIN_ID;
2154 req->id = newval;
2155 break;
2156 case GWL_HINSTANCE:
2157 req->flags = SET_WIN_INSTANCE;
2158 req->instance = (void *)newval;
2159 break;
2160 case GWL_USERDATA:
2161 req->flags = SET_WIN_USERDATA;
2162 req->user_data = (void *)newval;
2163 break;
2164 default:
2165 req->flags = SET_WIN_EXTRA;
2166 req->extra_offset = offset;
2167 req->extra_size = sizeof(newval);
2168 memcpy( &req->extra_value, &newval, sizeof(newval) );
2170 if ((ok = !wine_server_call_err( req )))
2172 switch(offset)
2174 case GWL_STYLE:
2175 wndPtr->dwStyle = newval;
2176 retval = reply->old_style;
2177 break;
2178 case GWL_EXSTYLE:
2179 wndPtr->dwExStyle = newval;
2180 retval = reply->old_ex_style;
2181 break;
2182 case GWL_ID:
2183 wndPtr->wIDmenu = newval;
2184 retval = reply->old_id;
2185 break;
2186 case GWL_HINSTANCE:
2187 wndPtr->hInstance = (HINSTANCE)newval;
2188 retval = (ULONG_PTR)reply->old_instance;
2189 break;
2190 case GWL_USERDATA:
2191 wndPtr->userdata = newval;
2192 retval = (ULONG_PTR)reply->old_user_data;
2193 break;
2194 default:
2196 void *ptr = (char *)wndPtr->wExtra + offset;
2197 memcpy( &retval, ptr, sizeof(retval) );
2198 memcpy( ptr, &newval, sizeof(newval) );
2200 break;
2204 SERVER_END_REQ;
2205 WIN_ReleasePtr( wndPtr );
2207 if (!ok) return 0;
2209 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2210 USER_Driver.pSetWindowStyle( hwnd, retval );
2212 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2213 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2215 return retval;
2219 /**********************************************************************
2220 * GetWindowLong (USER.135)
2222 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2224 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2228 /**********************************************************************
2229 * GetWindowLongA (USER32.@)
2231 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2233 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2237 /**********************************************************************
2238 * GetWindowLongW (USER32.@)
2240 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2242 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2246 /**********************************************************************
2247 * SetWindowLong (USER.136)
2249 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2251 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2255 /**********************************************************************
2256 * SetWindowLongA (USER32.@)
2258 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2260 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2264 /**********************************************************************
2265 * SetWindowLongW (USER32.@) Set window attribute
2267 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2268 * value in a window's extra memory.
2270 * The _hwnd_ parameter specifies the window. is the handle to a
2271 * window that has extra memory. The _newval_ parameter contains the
2272 * new attribute or extra memory value. If positive, the _offset_
2273 * parameter is the byte-addressed location in the window's extra
2274 * memory to set. If negative, _offset_ specifies the window
2275 * attribute to set, and should be one of the following values:
2277 * GWL_EXSTYLE The window's extended window style
2279 * GWL_STYLE The window's window style.
2281 * GWL_WNDPROC Pointer to the window's window procedure.
2283 * GWL_HINSTANCE The window's pplication instance handle.
2285 * GWL_ID The window's identifier.
2287 * GWL_USERDATA The window's user-specified data.
2289 * If the window is a dialog box, the _offset_ parameter can be one of
2290 * the following values:
2292 * DWL_DLGPROC The address of the window's dialog box procedure.
2294 * DWL_MSGRESULT The return value of a message
2295 * that the dialog box procedure processed.
2297 * DWL_USER Application specific information.
2299 * RETURNS
2301 * If successful, returns the previous value located at _offset_. Otherwise,
2302 * returns 0.
2304 * NOTES
2306 * Extra memory for a window class is specified by a nonzero cbWndExtra
2307 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2308 * time of class creation.
2310 * Using GWL_WNDPROC to set a new window procedure effectively creates
2311 * a window subclass. Use CallWindowProc() in the new windows procedure
2312 * to pass messages to the superclass's window procedure.
2314 * The user data is reserved for use by the application which created
2315 * the window.
2317 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2318 * instead, call the EnableWindow() function to change the window's
2319 * disabled state.
2321 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2322 * SetParent() instead.
2324 * Win95:
2325 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2326 * it sends WM_STYLECHANGING before changing the settings
2327 * and WM_STYLECHANGED afterwards.
2328 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2330 LONG WINAPI SetWindowLongW(
2331 HWND hwnd, /* [in] window to alter */
2332 INT offset, /* [in] offset, in bytes, of location to alter */
2333 LONG newval /* [in] new value of location */
2335 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2339 /*******************************************************************
2340 * GetWindowTextA (USER32.@)
2342 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2344 WCHAR *buffer;
2346 if (WIN_IsCurrentProcess( hwnd ))
2347 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2349 /* when window belongs to other process, don't send a message */
2350 if (nMaxCount <= 0) return 0;
2351 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2352 get_server_window_text( hwnd, buffer, nMaxCount );
2353 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2354 lpString[nMaxCount-1] = 0;
2355 HeapFree( GetProcessHeap(), 0, buffer );
2356 return strlen(lpString);
2360 /*******************************************************************
2361 * InternalGetWindowText (USER32.@)
2363 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2365 WND *win;
2367 if (nMaxCount <= 0) return 0;
2368 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2369 if (win != WND_OTHER_PROCESS)
2371 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2372 else lpString[0] = 0;
2373 WIN_ReleasePtr( win );
2375 else
2377 get_server_window_text( hwnd, lpString, nMaxCount );
2379 return strlenW(lpString);
2383 /*******************************************************************
2384 * GetWindowTextW (USER32.@)
2386 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2388 if (WIN_IsCurrentProcess( hwnd ))
2389 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2391 /* when window belongs to other process, don't send a message */
2392 if (nMaxCount <= 0) return 0;
2393 get_server_window_text( hwnd, lpString, nMaxCount );
2394 return strlenW(lpString);
2398 /*******************************************************************
2399 * SetWindowText (USER32.@)
2400 * SetWindowTextA (USER32.@)
2402 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2404 if (is_broadcast(hwnd))
2406 SetLastError( ERROR_INVALID_PARAMETER );
2407 return FALSE;
2409 if (!WIN_IsCurrentProcess( hwnd ))
2411 FIXME( "cannot set text %s of other process window %p\n", debugstr_a(lpString), hwnd );
2412 SetLastError( ERROR_ACCESS_DENIED );
2413 return FALSE;
2415 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2419 /*******************************************************************
2420 * SetWindowTextW (USER32.@)
2422 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2424 if (is_broadcast(hwnd))
2426 SetLastError( ERROR_INVALID_PARAMETER );
2427 return FALSE;
2429 if (!WIN_IsCurrentProcess( hwnd ))
2431 FIXME( "cannot set text %s of other process window %p\n", debugstr_w(lpString), hwnd );
2432 SetLastError( ERROR_ACCESS_DENIED );
2433 return FALSE;
2435 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2439 /*******************************************************************
2440 * GetWindowTextLengthA (USER32.@)
2442 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2444 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2447 /*******************************************************************
2448 * GetWindowTextLengthW (USER32.@)
2450 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2452 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2456 /*******************************************************************
2457 * IsWindow (USER32.@)
2459 BOOL WINAPI IsWindow( HWND hwnd )
2461 WND *ptr;
2462 BOOL ret;
2464 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2466 if (ptr != WND_OTHER_PROCESS)
2468 WIN_ReleasePtr( ptr );
2469 return TRUE;
2472 /* check other processes */
2473 SERVER_START_REQ( get_window_info )
2475 req->handle = hwnd;
2476 ret = !wine_server_call_err( req );
2478 SERVER_END_REQ;
2479 return ret;
2483 /***********************************************************************
2484 * GetWindowThreadProcessId (USER32.@)
2486 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2488 WND *ptr;
2489 DWORD tid = 0;
2491 if (!(ptr = WIN_GetPtr( hwnd )))
2493 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2494 return 0;
2497 if (ptr != WND_OTHER_PROCESS)
2499 /* got a valid window */
2500 tid = ptr->tid;
2501 if (process) *process = GetCurrentProcessId();
2502 WIN_ReleasePtr( ptr );
2503 return tid;
2506 /* check other processes */
2507 SERVER_START_REQ( get_window_info )
2509 req->handle = hwnd;
2510 if (!wine_server_call_err( req ))
2512 tid = (DWORD)reply->tid;
2513 if (process) *process = (DWORD)reply->pid;
2516 SERVER_END_REQ;
2517 return tid;
2521 /*****************************************************************
2522 * GetParent (USER32.@)
2524 HWND WINAPI GetParent( HWND hwnd )
2526 WND *wndPtr;
2527 HWND retvalue = 0;
2529 if (!(wndPtr = WIN_GetPtr( hwnd )))
2531 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2532 return 0;
2534 if (wndPtr == WND_OTHER_PROCESS)
2536 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2537 if (style & (WS_POPUP | WS_CHILD))
2539 SERVER_START_REQ( get_window_tree )
2541 req->handle = hwnd;
2542 if (!wine_server_call_err( req ))
2544 if (style & WS_POPUP) retvalue = reply->owner;
2545 else if (style & WS_CHILD) retvalue = reply->parent;
2548 SERVER_END_REQ;
2551 else
2553 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2554 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2555 WIN_ReleasePtr( wndPtr );
2557 return retvalue;
2561 /*****************************************************************
2562 * GetAncestor (USER32.@)
2564 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2566 WND *win;
2567 HWND *list, ret = 0;
2569 switch(type)
2571 case GA_PARENT:
2572 if (!(win = WIN_GetPtr( hwnd )))
2574 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2575 return 0;
2577 if (win != WND_OTHER_PROCESS)
2579 ret = win->parent;
2580 WIN_ReleasePtr( win );
2582 else /* need to query the server */
2584 SERVER_START_REQ( get_window_tree )
2586 req->handle = hwnd;
2587 if (!wine_server_call_err( req )) ret = reply->parent;
2589 SERVER_END_REQ;
2591 break;
2593 case GA_ROOT:
2594 if (!(list = WIN_ListParents( hwnd ))) return 0;
2596 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2597 else
2599 int count = 2;
2600 while (list[count]) count++;
2601 ret = list[count - 2]; /* get the one before the desktop */
2603 HeapFree( GetProcessHeap(), 0, list );
2604 break;
2606 case GA_ROOTOWNER:
2607 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2608 for (;;)
2610 HWND parent = GetParent( ret );
2611 if (!parent) break;
2612 ret = parent;
2614 break;
2616 return ret;
2620 /*****************************************************************
2621 * SetParent (USER32.@)
2623 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2625 WND *wndPtr;
2626 HWND retvalue, full_handle;
2627 BOOL was_visible;
2629 if (is_broadcast(hwnd) || is_broadcast(parent))
2631 SetLastError(ERROR_INVALID_PARAMETER);
2632 return 0;
2635 if (!parent) parent = GetDesktopWindow();
2636 else parent = WIN_GetFullHandle( parent );
2638 if (!IsWindow( parent ))
2640 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2641 return 0;
2644 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2645 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2647 hwnd = full_handle;
2649 if (USER_Driver.pSetParent)
2650 return USER_Driver.pSetParent( hwnd, parent );
2652 /* Windows hides the window first, then shows it again
2653 * including the WM_SHOWWINDOW messages and all */
2654 was_visible = ShowWindow( hwnd, SW_HIDE );
2656 if (!IsWindow( parent )) return 0;
2657 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2659 retvalue = wndPtr->parent; /* old parent */
2660 if (parent != retvalue)
2662 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2664 if (parent != GetDesktopWindow()) /* a child window */
2666 if (!(wndPtr->dwStyle & WS_CHILD))
2668 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2669 if (menu) DestroyMenu( menu );
2673 WIN_ReleasePtr( wndPtr );
2675 /* SetParent additionally needs to make hwnd the topmost window
2676 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2677 WM_WINDOWPOSCHANGED notification messages.
2679 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2680 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2681 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2682 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2683 return retvalue;
2687 /*******************************************************************
2688 * IsChild (USER32.@)
2690 BOOL WINAPI IsChild( HWND parent, HWND child )
2692 HWND *list = WIN_ListParents( child );
2693 int i;
2694 BOOL ret;
2696 if (!list) return FALSE;
2697 parent = WIN_GetFullHandle( parent );
2698 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2699 ret = (list[i] != 0);
2700 HeapFree( GetProcessHeap(), 0, list );
2701 return ret;
2705 /***********************************************************************
2706 * IsWindowVisible (USER32.@)
2708 BOOL WINAPI IsWindowVisible( HWND hwnd )
2710 HWND *list;
2711 BOOL retval;
2712 int i;
2714 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2715 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2716 for (i = 0; list[i]; i++)
2717 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2718 retval = !list[i];
2719 HeapFree( GetProcessHeap(), 0, list );
2720 return retval;
2724 /***********************************************************************
2725 * WIN_IsWindowDrawable
2727 * hwnd is drawable when it is visible, all parents are not
2728 * minimized, and it is itself not minimized unless we are
2729 * trying to draw its default class icon.
2731 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2733 HWND *list;
2734 BOOL retval;
2735 int i;
2736 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2738 if (!(style & WS_VISIBLE)) return FALSE;
2739 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2741 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2742 for (i = 0; list[i]; i++)
2743 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2744 break;
2745 retval = !list[i];
2746 HeapFree( GetProcessHeap(), 0, list );
2747 return retval;
2751 /*******************************************************************
2752 * GetTopWindow (USER32.@)
2754 HWND WINAPI GetTopWindow( HWND hwnd )
2756 if (!hwnd) hwnd = GetDesktopWindow();
2757 return GetWindow( hwnd, GW_CHILD );
2761 /*******************************************************************
2762 * GetWindow (USER32.@)
2764 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2766 HWND retval = 0;
2768 if (rel == GW_OWNER) /* this one may be available locally */
2770 WND *wndPtr = WIN_GetPtr( hwnd );
2771 if (!wndPtr)
2773 SetLastError( ERROR_INVALID_HANDLE );
2774 return 0;
2776 if (wndPtr != WND_OTHER_PROCESS)
2778 retval = wndPtr->owner;
2779 WIN_ReleasePtr( wndPtr );
2780 return retval;
2782 /* else fall through to server call */
2785 SERVER_START_REQ( get_window_tree )
2787 req->handle = hwnd;
2788 if (!wine_server_call_err( req ))
2790 switch(rel)
2792 case GW_HWNDFIRST:
2793 retval = reply->first_sibling;
2794 break;
2795 case GW_HWNDLAST:
2796 retval = reply->last_sibling;
2797 break;
2798 case GW_HWNDNEXT:
2799 retval = reply->next_sibling;
2800 break;
2801 case GW_HWNDPREV:
2802 retval = reply->prev_sibling;
2803 break;
2804 case GW_OWNER:
2805 retval = reply->owner;
2806 break;
2807 case GW_CHILD:
2808 retval = reply->first_child;
2809 break;
2813 SERVER_END_REQ;
2814 return retval;
2818 /***********************************************************************
2819 * WIN_InternalShowOwnedPopups
2821 * Internal version of ShowOwnedPopups; Wine functions should use this
2822 * to avoid interfering with application calls to ShowOwnedPopups
2823 * and to make sure the application can't prevent showing/hiding.
2825 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2829 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2831 int count = 0;
2832 WND *pWnd;
2833 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2835 if (!win_array) return TRUE;
2838 * Show windows Lowest first, Highest last to preserve Z-Order
2840 while (win_array[count]) count++;
2841 while (--count >= 0)
2843 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2844 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2846 if (pWnd->dwStyle & WS_POPUP)
2848 if (fShow)
2850 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2851 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2854 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2856 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2857 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2860 else
2862 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2863 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2864 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2867 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2869 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2870 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2871 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2875 WIN_ReleaseWndPtr( pWnd );
2877 HeapFree( GetProcessHeap(), 0, win_array );
2879 return TRUE;
2882 /*******************************************************************
2883 * ShowOwnedPopups (USER32.@)
2885 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2887 int count = 0;
2888 WND *pWnd;
2889 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2891 if (!win_array) return TRUE;
2893 while (win_array[count]) count++;
2894 while (--count >= 0)
2896 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2897 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2899 if (pWnd->dwStyle & WS_POPUP)
2901 if (fShow)
2903 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2905 /* In Windows, ShowOwnedPopups(TRUE) generates
2906 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2907 * regardless of the state of the owner
2909 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2910 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2913 else
2915 if (IsWindowVisible(pWnd->hwndSelf))
2917 /* In Windows, ShowOwnedPopups(FALSE) generates
2918 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2919 * regardless of the state of the owner
2921 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2922 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2926 WIN_ReleaseWndPtr( pWnd );
2928 HeapFree( GetProcessHeap(), 0, win_array );
2929 return TRUE;
2933 /*******************************************************************
2934 * GetLastActivePopup (USER32.@)
2936 HWND WINAPI GetLastActivePopup( HWND hwnd )
2938 HWND retval = hwnd;
2940 SERVER_START_REQ( get_window_info )
2942 req->handle = hwnd;
2943 if (!wine_server_call_err( req )) retval = reply->last_active;
2945 SERVER_END_REQ;
2946 return retval;
2950 /*******************************************************************
2951 * WIN_ListParents
2953 * Build an array of all parents of a given window, starting with
2954 * the immediate parent. The array must be freed with HeapFree.
2955 * Returns NULL if window is a top-level window.
2957 HWND *WIN_ListParents( HWND hwnd )
2959 WND *win;
2960 HWND current, *list;
2961 int pos = 0, size = 16, count = 0;
2963 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2965 current = hwnd;
2966 for (;;)
2968 if (!(win = WIN_GetPtr( current ))) goto empty;
2969 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2970 list[pos] = win->parent;
2971 WIN_ReleasePtr( win );
2972 if (!(current = list[pos]))
2974 if (!pos) goto empty;
2975 return list;
2977 if (++pos == size - 1)
2979 /* need to grow the list */
2980 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2981 if (!new_list) goto empty;
2982 list = new_list;
2983 size += 16;
2987 /* at least one parent belongs to another process, have to query the server */
2989 for (;;)
2991 count = 0;
2992 SERVER_START_REQ( get_window_parents )
2994 req->handle = hwnd;
2995 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2996 if (!wine_server_call( req )) count = reply->count;
2998 SERVER_END_REQ;
2999 if (!count) goto empty;
3000 if (size > count)
3002 list[count] = 0;
3003 return list;
3005 HeapFree( GetProcessHeap(), 0, list );
3006 size = count + 1;
3007 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
3010 empty:
3011 HeapFree( GetProcessHeap(), 0, list );
3012 return NULL;
3016 /*******************************************************************
3017 * WIN_ListChildren
3019 * Build an array of the children of a given window. The array must be
3020 * freed with HeapFree. Returns NULL when no windows are found.
3022 HWND *WIN_ListChildren( HWND hwnd )
3024 return list_window_children( hwnd, 0, 0 );
3028 /*******************************************************************
3029 * EnumWindows (USER32.@)
3031 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3033 HWND *list;
3034 BOOL ret = TRUE;
3035 int i, iWndsLocks;
3037 /* We have to build a list of all windows first, to avoid */
3038 /* unpleasant side-effects, for instance if the callback */
3039 /* function changes the Z-order of the windows. */
3041 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3043 /* Now call the callback function for every window */
3045 iWndsLocks = WIN_SuspendWndsLock();
3046 for (i = 0; list[i]; i++)
3048 /* Make sure that the window still exists */
3049 if (!IsWindow( list[i] )) continue;
3050 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3052 WIN_RestoreWndsLock(iWndsLocks);
3053 HeapFree( GetProcessHeap(), 0, list );
3054 return ret;
3058 /**********************************************************************
3059 * EnumThreadWindows (USER32.@)
3061 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3063 HWND *list;
3064 int i, iWndsLocks;
3066 if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
3068 /* Now call the callback function for every window */
3070 iWndsLocks = WIN_SuspendWndsLock();
3071 for (i = 0; list[i]; i++)
3072 if (!func( list[i], lParam )) break;
3073 WIN_RestoreWndsLock(iWndsLocks);
3074 HeapFree( GetProcessHeap(), 0, list );
3075 return TRUE;
3079 /**********************************************************************
3080 * WIN_EnumChildWindows
3082 * Helper function for EnumChildWindows().
3084 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3086 HWND *childList;
3087 BOOL ret = FALSE;
3089 for ( ; *list; list++)
3091 /* Make sure that the window still exists */
3092 if (!IsWindow( *list )) continue;
3093 /* skip owned windows */
3094 if (GetWindow( *list, GW_OWNER )) continue;
3095 /* Build children list first */
3096 childList = WIN_ListChildren( *list );
3098 ret = func( *list, lParam );
3100 if (childList)
3102 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3103 HeapFree( GetProcessHeap(), 0, childList );
3105 if (!ret) return FALSE;
3107 return TRUE;
3111 /**********************************************************************
3112 * EnumChildWindows (USER32.@)
3114 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3116 HWND *list;
3117 int iWndsLocks;
3119 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3120 iWndsLocks = WIN_SuspendWndsLock();
3121 WIN_EnumChildWindows( list, func, lParam );
3122 WIN_RestoreWndsLock(iWndsLocks);
3123 HeapFree( GetProcessHeap(), 0, list );
3124 return TRUE;
3128 /*******************************************************************
3129 * AnyPopup (USER.52)
3131 BOOL16 WINAPI AnyPopup16(void)
3133 return AnyPopup();
3137 /*******************************************************************
3138 * AnyPopup (USER32.@)
3140 BOOL WINAPI AnyPopup(void)
3142 int i;
3143 BOOL retvalue;
3144 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3146 if (!list) return FALSE;
3147 for (i = 0; list[i]; i++)
3149 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3151 retvalue = (list[i] != 0);
3152 HeapFree( GetProcessHeap(), 0, list );
3153 return retvalue;
3157 /*******************************************************************
3158 * FlashWindow (USER32.@)
3160 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3162 WND *wndPtr = WIN_FindWndPtr(hWnd);
3164 TRACE("%p\n", hWnd);
3166 if (!wndPtr) return FALSE;
3167 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3169 if (wndPtr->dwStyle & WS_MINIMIZE)
3171 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3173 HDC hDC = GetDC(hWnd);
3175 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM)hDC, 0 ))
3176 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3178 ReleaseDC( hWnd, hDC );
3179 wndPtr->flags |= WIN_NCACTIVATED;
3181 else
3183 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3184 wndPtr->flags &= ~WIN_NCACTIVATED;
3186 WIN_ReleaseWndPtr(wndPtr);
3187 return TRUE;
3189 else
3191 WPARAM16 wparam;
3192 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3193 else wparam = (hWnd == GetForegroundWindow());
3195 WIN_ReleaseWndPtr(wndPtr);
3196 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3197 return wparam;
3201 /*******************************************************************
3202 * FlashWindowEx (USER32.@)
3204 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3206 FIXME("%p\n", pfwi);
3207 return TRUE;
3210 /*******************************************************************
3211 * GetWindowContextHelpId (USER32.@)
3213 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3215 DWORD retval;
3216 WND *wnd = WIN_FindWndPtr( hwnd );
3217 if (!wnd) return 0;
3218 retval = wnd->helpContext;
3219 WIN_ReleaseWndPtr(wnd);
3220 return retval;
3224 /*******************************************************************
3225 * SetWindowContextHelpId (USER32.@)
3227 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3229 WND *wnd = WIN_FindWndPtr( hwnd );
3230 if (!wnd) return FALSE;
3231 wnd->helpContext = id;
3232 WIN_ReleaseWndPtr(wnd);
3233 return TRUE;
3237 /*******************************************************************
3238 * DragDetect (USER32.@)
3240 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3242 MSG msg;
3243 RECT rect;
3245 rect.left = pt.x - wDragWidth;
3246 rect.right = pt.x + wDragWidth;
3248 rect.top = pt.y - wDragHeight;
3249 rect.bottom = pt.y + wDragHeight;
3251 SetCapture(hWnd);
3253 while(1)
3255 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3257 if( msg.message == WM_LBUTTONUP )
3259 ReleaseCapture();
3260 return 0;
3262 if( msg.message == WM_MOUSEMOVE )
3264 POINT tmp;
3265 tmp.x = LOWORD(msg.lParam);
3266 tmp.y = HIWORD(msg.lParam);
3267 if( !PtInRect( &rect, tmp ))
3269 ReleaseCapture();
3270 return 1;
3274 WaitMessage();
3276 return 0;
3279 /******************************************************************************
3280 * GetWindowModuleFileNameA (USER32.@)
3282 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3284 FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3285 hwnd, lpszFileName, cchFileNameMax);
3286 return 0;
3289 /******************************************************************************
3290 * GetWindowModuleFileNameW (USER32.@)
3292 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3294 FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3295 hwnd, lpszFileName, cchFileNameMax);
3296 return 0;
3299 /******************************************************************************
3300 * GetWindowInfo (USER32.@)
3301 * hwnd: in
3302 * pwi: out.
3303 * MS Documentation mentions that pwi->cbSize must be set to SIZEOF(WINDOWINFO)
3304 * this may be because this structure changed over time. If this is the
3305 * the case, then please: FIXME.
3306 * Using the structure described in MSDN for 98/ME/NT(4.0 SP3)/2000/XP.
3308 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3310 if (!pwi) return FALSE;
3311 if (pwi->cbSize != sizeof(WINDOWINFO))
3313 FIXME("windowinfo->cbSize != sizeof(WINDOWINFO). Please report\n");
3314 return FALSE;
3316 if (!IsWindow(hwnd)) return FALSE;
3318 GetWindowRect(hwnd, &pwi->rcWindow);
3319 GetClientRect(hwnd, &pwi->rcClient);
3320 /* translate to screen coordinates */
3321 MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3323 pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3324 pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3325 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3327 pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3328 pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3330 pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3331 pwi->wCreatorVersion = 0x0400;
3333 return TRUE;