Fixed another regression in PlaySound.
[wine.git] / windows / win.c
blob551d56c607323f03688a8af3bd73acf4000f60d3
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 <stdlib.h>
26 #include <string.h>
27 #include "windef.h"
28 #include "wine/winbase16.h"
29 #include "wine/winuser16.h"
30 #include "wine/server.h"
31 #include "wine/unicode.h"
32 #include "win.h"
33 #include "user.h"
34 #include "dce.h"
35 #include "controls.h"
36 #include "cursoricon.h"
37 #include "hook.h"
38 #include "message.h"
39 #include "queue.h"
40 #include "task.h"
41 #include "winpos.h"
42 #include "winerror.h"
43 #include "stackframe.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(win);
47 WINE_DECLARE_DEBUG_CHANNEL(msg);
49 #define NB_USER_HANDLES (LAST_USER_HANDLE - FIRST_USER_HANDLE + 1)
51 /**********************************************************************/
53 /* Desktop window */
54 static WND *pWndDesktop = NULL;
56 static WORD wDragWidth = 4;
57 static WORD wDragHeight= 3;
59 static void *user_handles[NB_USER_HANDLES];
61 /* thread safeness */
62 extern SYSLEVEL USER_SysLevel; /* FIXME */
64 /***********************************************************************
65 * WIN_SuspendWndsLock
67 * Suspend the lock on WND structures.
68 * Returns the number of locks suspended
70 int WIN_SuspendWndsLock( void )
72 int isuspendedLocks = _ConfirmSysLevel( &USER_SysLevel );
73 int count = isuspendedLocks;
75 while ( count-- > 0 )
76 _LeaveSysLevel( &USER_SysLevel );
78 return isuspendedLocks;
81 /***********************************************************************
82 * WIN_RestoreWndsLock
84 * Restore the suspended locks on WND structures
86 void WIN_RestoreWndsLock( int ipreviousLocks )
88 while ( ipreviousLocks-- > 0 )
89 _EnterSysLevel( &USER_SysLevel );
92 /***********************************************************************
93 * create_window_handle
95 * Create a window handle with the server.
97 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, INT size )
99 BOOL res;
100 user_handle_t handle = 0;
101 WORD index;
102 WND *win = HeapAlloc( GetProcessHeap(), 0, size );
104 if (!win) return NULL;
106 USER_Lock();
108 SERVER_START_REQ( create_window )
110 req->parent = parent;
111 req->owner = owner;
112 req->atom = atom;
113 if ((res = !wine_server_call_err( req ))) handle = reply->handle;
115 SERVER_END_REQ;
117 if (!res)
119 USER_Unlock();
120 HeapFree( GetProcessHeap(), 0, win );
121 return NULL;
123 index = LOWORD(handle) - FIRST_USER_HANDLE;
124 assert( index < NB_USER_HANDLES );
125 user_handles[index] = win;
126 win->hwndSelf = handle;
127 win->dwMagic = WND_MAGIC;
128 win->irefCount = 1;
129 return win;
133 /***********************************************************************
134 * free_window_handle
136 * Free a window handle.
138 static WND *free_window_handle( HWND hwnd )
140 WND *ptr;
141 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
143 if (index >= NB_USER_HANDLES) return NULL;
144 USER_Lock();
145 if ((ptr = user_handles[index]))
147 SERVER_START_REQ( destroy_window )
149 req->handle = hwnd;
150 if (!wine_server_call_err( req ))
151 user_handles[index] = NULL;
152 else
153 ptr = NULL;
155 SERVER_END_REQ;
157 USER_Unlock();
158 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
159 return ptr;
163 /*******************************************************************
164 * list_window_children
166 * Build an array of the children of a given window. The array must be
167 * freed with HeapFree. Returns NULL when no windows are found.
169 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
171 HWND *list;
172 int size = 32;
174 for (;;)
176 int count = 0;
178 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
180 SERVER_START_REQ( get_window_children )
182 req->parent = hwnd;
183 req->atom = atom;
184 req->tid = (void *)tid;
185 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
186 if (!wine_server_call( req )) count = reply->count;
188 SERVER_END_REQ;
189 if (count && count < size)
191 list[count] = 0;
192 return list;
194 HeapFree( GetProcessHeap(), 0, list );
195 if (!count) break;
196 size = count + 1; /* restart with a large enough buffer */
198 return NULL;
202 /*******************************************************************
203 * send_parent_notify
205 static void send_parent_notify( HWND hwnd, UINT msg )
207 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) return;
208 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) return;
209 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
210 MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
214 /*******************************************************************
215 * get_server_window_text
217 * Retrieve the window text from the server.
219 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
221 size_t len = 0;
223 SERVER_START_REQ( get_window_text )
225 req->handle = hwnd;
226 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
227 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
229 SERVER_END_REQ;
230 text[len / sizeof(WCHAR)] = 0;
234 /***********************************************************************
235 * WIN_GetPtr
237 * Return a pointer to the WND structure if local to the process,
238 * or WND_OTHER_PROCESS is handle may be valid in other process.
239 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
241 WND *WIN_GetPtr( HWND hwnd )
243 WND * ptr;
244 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
246 if (index >= NB_USER_HANDLES) return NULL;
248 USER_Lock();
249 if ((ptr = user_handles[index]))
251 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
252 return ptr;
253 ptr = NULL;
255 else ptr = WND_OTHER_PROCESS;
256 USER_Unlock();
257 return ptr;
261 /***********************************************************************
262 * WIN_IsCurrentProcess
264 * Check whether a given window belongs to the current process (and return the full handle).
266 HWND WIN_IsCurrentProcess( HWND hwnd )
268 WND *ptr;
269 HWND ret;
271 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
272 ret = ptr->hwndSelf;
273 WIN_ReleasePtr( ptr );
274 return ret;
278 /***********************************************************************
279 * WIN_IsCurrentThread
281 * Check whether a given window belongs to the current thread (and return the full handle).
283 HWND WIN_IsCurrentThread( HWND hwnd )
285 WND *ptr;
286 HWND ret = 0;
288 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
290 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
291 WIN_ReleasePtr( ptr );
293 return ret;
297 /***********************************************************************
298 * WIN_Handle32
300 * Convert a 16-bit window handle to a full 32-bit handle.
302 HWND WIN_Handle32( HWND16 hwnd16 )
304 WND *ptr;
305 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
307 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
308 /* do sign extension for -2 and -3 */
309 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
311 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
313 if (ptr != WND_OTHER_PROCESS)
315 hwnd = ptr->hwndSelf;
316 WIN_ReleasePtr( ptr );
318 else /* may belong to another process */
320 SERVER_START_REQ( get_window_info )
322 req->handle = hwnd;
323 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
325 SERVER_END_REQ;
327 return hwnd;
331 /***********************************************************************
332 * WIN_FindWndPtr
334 * Return a pointer to the WND structure corresponding to a HWND.
336 WND * WIN_FindWndPtr( HWND hwnd )
338 WND * ptr;
340 if (!hwnd) return NULL;
342 if ((ptr = WIN_GetPtr( hwnd )))
344 if (ptr != WND_OTHER_PROCESS)
346 /* increment destruction monitoring */
347 ptr->irefCount++;
348 return ptr;
350 if (IsWindow( hwnd )) /* check other processes */
352 ERR( "window %04x belongs to other process\n", hwnd );
353 /* DbgBreakPoint(); */
356 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
357 return NULL;
361 /***********************************************************************
362 * WIN_ReleaseWndPtr
364 * Release the pointer to the WND structure.
366 void WIN_ReleaseWndPtr(WND *wndPtr)
368 if(!wndPtr) return;
370 /* Decrement destruction monitoring value */
371 wndPtr->irefCount--;
372 /* Check if it's time to release the memory */
373 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
375 /* Release memory */
376 free_window_handle( wndPtr->hwndSelf );
378 else if(wndPtr->irefCount < 0)
380 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
381 ERR("forgot a Lock on %p somewhere\n",wndPtr);
383 /* unlock all WND structures for thread safeness */
384 USER_Unlock();
388 /***********************************************************************
389 * WIN_UnlinkWindow
391 * Remove a window from the siblings linked list.
393 void WIN_UnlinkWindow( HWND hwnd )
395 WIN_LinkWindow( hwnd, 0, 0 );
399 /***********************************************************************
400 * WIN_LinkWindow
402 * Insert a window into the siblings linked list.
403 * The window is inserted after the specified window, which can also
404 * be specified as HWND_TOP or HWND_BOTTOM.
405 * If parent is 0, window is unlinked from the tree.
407 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
409 WND *wndPtr = WIN_GetPtr( hwnd );
411 if (!wndPtr) return;
412 if (wndPtr == WND_OTHER_PROCESS)
414 if (IsWindow(hwnd)) ERR(" cannot link other process window %x\n", hwnd );
415 return;
418 SERVER_START_REQ( link_window )
420 req->handle = hwnd;
421 req->parent = parent;
422 req->previous = hwndInsertAfter;
423 if (!wine_server_call( req ))
425 if (reply->full_parent && reply->full_parent != wndPtr->parent)
427 wndPtr->owner = 0; /* reset owner when changing parent */
428 wndPtr->parent = reply->full_parent;
433 SERVER_END_REQ;
434 WIN_ReleasePtr( wndPtr );
438 /***********************************************************************
439 * WIN_SetOwner
441 * Change the owner of a window.
443 void WIN_SetOwner( HWND hwnd, HWND owner )
445 WND *win = WIN_GetPtr( hwnd );
447 if (!win) return;
448 if (win == WND_OTHER_PROCESS)
450 if (IsWindow(hwnd)) ERR( "cannot set owner %x on other process window %x\n", owner, hwnd );
451 return;
453 SERVER_START_REQ( set_window_owner )
455 req->handle = hwnd;
456 req->owner = owner;
457 if (!wine_server_call( req )) win->owner = reply->full_owner;
459 SERVER_END_REQ;
460 WIN_ReleasePtr( win );
464 /***********************************************************************
465 * WIN_SetStyle
467 * Change the style of a window.
469 LONG WIN_SetStyle( HWND hwnd, LONG style )
471 BOOL ok;
472 LONG ret = 0;
473 WND *win = WIN_GetPtr( hwnd );
475 if (!win) return 0;
476 if (win == WND_OTHER_PROCESS)
478 if (IsWindow(hwnd))
479 ERR( "cannot set style %lx on other process window %x\n", style, hwnd );
480 return 0;
482 if (style == win->dwStyle)
484 WIN_ReleasePtr( win );
485 return style;
487 SERVER_START_REQ( set_window_info )
489 req->handle = hwnd;
490 req->flags = SET_WIN_STYLE;
491 req->style = style;
492 if ((ok = !wine_server_call( req )))
494 ret = reply->old_style;
495 win->dwStyle = style;
498 SERVER_END_REQ;
499 WIN_ReleasePtr( win );
500 if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
501 return ret;
505 /***********************************************************************
506 * WIN_SetExStyle
508 * Change the extended style of a window.
510 LONG WIN_SetExStyle( HWND hwnd, LONG style )
512 LONG ret = 0;
513 WND *win = WIN_GetPtr( hwnd );
515 if (!win) return 0;
516 if (win == WND_OTHER_PROCESS)
518 if (IsWindow(hwnd))
519 ERR( "cannot set exstyle %lx on other process window %x\n", style, hwnd );
520 return 0;
522 if (style == win->dwExStyle)
524 WIN_ReleasePtr( win );
525 return style;
527 SERVER_START_REQ( set_window_info )
529 req->handle = hwnd;
530 req->flags = SET_WIN_EXSTYLE;
531 req->ex_style = style;
532 if (!wine_server_call( req ))
534 ret = reply->old_ex_style;
535 win->dwExStyle = style;
538 SERVER_END_REQ;
539 WIN_ReleasePtr( win );
540 return ret;
544 /***********************************************************************
545 * WIN_SetRectangles
547 * Set the window and client rectangles.
549 void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient )
551 WND *win = WIN_GetPtr( hwnd );
552 BOOL ret;
554 if (!win) return;
555 if (win == WND_OTHER_PROCESS)
557 if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %x\n", hwnd );
558 return;
560 SERVER_START_REQ( set_window_rectangles )
562 req->handle = hwnd;
563 req->window.left = rectWindow->left;
564 req->window.top = rectWindow->top;
565 req->window.right = rectWindow->right;
566 req->window.bottom = rectWindow->bottom;
567 req->client.left = rectClient->left;
568 req->client.top = rectClient->top;
569 req->client.right = rectClient->right;
570 req->client.bottom = rectClient->bottom;
571 ret = !wine_server_call( req );
573 SERVER_END_REQ;
574 if (ret)
576 win->rectWindow = *rectWindow;
577 win->rectClient = *rectClient;
579 TRACE( "win %x window (%d,%d)-(%d,%d) client (%d,%d)-(%d,%d)\n", hwnd,
580 rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom,
581 rectClient->left, rectClient->top, rectClient->right, rectClient->bottom );
583 WIN_ReleasePtr( win );
587 /***********************************************************************
588 * WIN_GetRectangles
590 * Get the window and client rectangles.
592 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
594 WND *win = WIN_GetPtr( hwnd );
595 BOOL ret = TRUE;
597 if (!win) return FALSE;
598 if (win == WND_OTHER_PROCESS)
600 SERVER_START_REQ( get_window_rectangles )
602 req->handle = hwnd;
603 if ((ret = !wine_server_call( req )))
605 if (rectWindow)
607 rectWindow->left = reply->window.left;
608 rectWindow->top = reply->window.top;
609 rectWindow->right = reply->window.right;
610 rectWindow->bottom = reply->window.bottom;
612 if (rectClient)
614 rectClient->left = reply->client.left;
615 rectClient->top = reply->client.top;
616 rectClient->right = reply->client.right;
617 rectClient->bottom = reply->client.bottom;
621 SERVER_END_REQ;
623 else
625 if (rectWindow) *rectWindow = win->rectWindow;
626 if (rectClient) *rectClient = win->rectClient;
627 WIN_ReleasePtr( win );
629 return ret;
633 /***********************************************************************
634 * WIN_DestroyWindow
636 * Destroy storage associated to a window. "Internals" p.358
638 LRESULT WIN_DestroyWindow( HWND hwnd )
640 WND *wndPtr;
641 HWND *list;
643 TRACE("%04x\n", hwnd );
645 if (!(hwnd = WIN_IsCurrentThread( hwnd )))
647 ERR( "window doesn't belong to current thread\n" );
648 return 0;
651 /* free child windows */
652 if ((list = WIN_ListChildren( hwnd )))
654 int i;
655 for (i = 0; list[i]; i++)
657 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
658 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
660 HeapFree( GetProcessHeap(), 0, list );
664 * Clear the update region to make sure no WM_PAINT messages will be
665 * generated for this window while processing the WM_NCDESTROY.
667 RedrawWindow( hwnd, NULL, 0,
668 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
671 * Send the WM_NCDESTROY to the window being destroyed.
673 SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
675 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
677 WINPOS_CheckInternalPos( hwnd );
678 if( hwnd == GetCapture()) ReleaseCapture();
680 /* free resources associated with the window */
682 TIMER_RemoveWindowTimers( hwnd );
684 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
685 wndPtr->hmemTaskQ = 0;
687 if (!(wndPtr->dwStyle & WS_CHILD))
689 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
690 if (menu) DestroyMenu( menu );
692 if (wndPtr->hSysMenu)
694 DestroyMenu( wndPtr->hSysMenu );
695 wndPtr->hSysMenu = 0;
697 USER_Driver.pDestroyWindow( hwnd );
698 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
699 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
700 CLASS_RemoveWindow( wndPtr->class );
701 wndPtr->class = NULL;
702 wndPtr->dwMagic = 0; /* Mark it as invalid */
703 WIN_ReleaseWndPtr( wndPtr );
704 return 0;
707 /***********************************************************************
708 * WIN_DestroyThreadWindows
710 * Destroy all children of 'wnd' owned by the current thread.
711 * Return TRUE if something was done.
713 void WIN_DestroyThreadWindows( HWND hwnd )
715 HWND *list;
716 int i;
718 if (!(list = WIN_ListChildren( hwnd ))) return;
719 for (i = 0; list[i]; i++)
721 if (WIN_IsCurrentThread( list[i] ))
722 DestroyWindow( list[i] );
723 else
724 WIN_DestroyThreadWindows( list[i] );
726 HeapFree( GetProcessHeap(), 0, list );
729 /***********************************************************************
730 * WIN_CreateDesktopWindow
732 * Create the desktop window.
734 BOOL WIN_CreateDesktopWindow(void)
736 struct tagCLASS *class;
737 HWND hwndDesktop;
738 INT wndExtra;
739 DWORD clsStyle;
740 WNDPROC winproc;
741 DCE *dce;
742 CREATESTRUCTA cs;
743 RECT rect;
745 TRACE("Creating desktop window\n");
747 if (!WINPOS_CreateInternalPosAtom() ||
748 !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
749 &wndExtra, &winproc, &clsStyle, &dce )))
750 return FALSE;
752 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM),
753 sizeof(WND) + wndExtra - sizeof(pWndDesktop->wExtra) );
754 if (!pWndDesktop) return FALSE;
755 hwndDesktop = pWndDesktop->hwndSelf;
757 pWndDesktop->tid = 0; /* nobody owns the desktop */
758 pWndDesktop->parent = 0;
759 pWndDesktop->owner = 0;
760 pWndDesktop->class = class;
761 pWndDesktop->hInstance = 0;
762 pWndDesktop->text = NULL;
763 pWndDesktop->hmemTaskQ = 0;
764 pWndDesktop->hrgnUpdate = 0;
765 pWndDesktop->hwndLastActive = hwndDesktop;
766 pWndDesktop->dwStyle = 0;
767 pWndDesktop->dwExStyle = 0;
768 pWndDesktop->clsStyle = clsStyle;
769 pWndDesktop->dce = NULL;
770 pWndDesktop->pVScroll = NULL;
771 pWndDesktop->pHScroll = NULL;
772 pWndDesktop->wIDmenu = 0;
773 pWndDesktop->helpContext = 0;
774 pWndDesktop->flags = 0;
775 pWndDesktop->hSysMenu = 0;
776 pWndDesktop->userdata = 0;
777 pWndDesktop->winproc = winproc;
778 pWndDesktop->cbWndExtra = wndExtra;
780 cs.lpCreateParams = NULL;
781 cs.hInstance = 0;
782 cs.hMenu = 0;
783 cs.hwndParent = 0;
784 cs.x = 0;
785 cs.y = 0;
786 cs.cx = GetSystemMetrics( SM_CXSCREEN );
787 cs.cy = GetSystemMetrics( SM_CYSCREEN );
788 cs.style = pWndDesktop->dwStyle;
789 cs.dwExStyle = pWndDesktop->dwExStyle;
790 cs.lpszName = NULL;
791 cs.lpszClass = DESKTOP_CLASS_ATOM;
793 SetRect( &rect, 0, 0, cs.cx, cs.cy );
794 WIN_SetRectangles( hwndDesktop, &rect, &rect );
795 WIN_SetStyle( hwndDesktop, WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
797 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
799 WIN_ReleaseWndPtr( pWndDesktop );
800 return FALSE;
803 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
804 WIN_ReleaseWndPtr( pWndDesktop );
805 return TRUE;
809 /***********************************************************************
810 * WIN_FixCoordinates
812 * Fix the coordinates - Helper for WIN_CreateWindowEx.
813 * returns default show mode in sw.
814 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
816 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
818 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
819 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
821 if (cs->style & (WS_CHILD | WS_POPUP))
823 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
824 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
826 else /* overlapped window */
828 STARTUPINFOA info;
830 GetStartupInfoA( &info );
832 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
834 /* Never believe Microsoft's documentation... CreateWindowEx doc says
835 * that if an overlapped window is created with WS_VISIBLE style bit
836 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
837 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
838 * reveals that
840 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
841 * 2) it does not ignore the y parameter as the docs claim; instead, it
842 * uses it as second parameter to ShowWindow() unless y is either
843 * CW_USEDEFAULT or CW_USEDEFAULT16.
845 * The fact that we didn't do 2) caused bogus windows pop up when wine
846 * was running apps that were using this obscure feature. Example -
847 * calc.exe that comes with Win98 (only Win98, it's different from
848 * the one that comes with Win95 and NT)
850 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
851 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
852 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
855 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
857 if (info.dwFlags & STARTF_USESIZE)
859 cs->cx = info.dwXSize;
860 cs->cy = info.dwYSize;
862 else /* if no other hint from the app, pick 3/4 of the screen real estate */
864 RECT r;
865 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
866 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
867 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
872 else
874 /* neither x nor cx are default. Check the y values .
875 * In the trace we see Outlook and Outlook Express using
876 * cy set to CW_USEDEFAULT when opening the address book.
878 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
879 RECT r;
880 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
881 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
882 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
887 /***********************************************************************
888 * dump_window_styles
890 static void dump_window_styles( DWORD style, DWORD exstyle )
892 TRACE( "style:" );
893 if(style & WS_POPUP) DPRINTF(" WS_POPUP");
894 if(style & WS_CHILD) DPRINTF(" WS_CHILD");
895 if(style & WS_MINIMIZE) DPRINTF(" WS_MINIMIZE");
896 if(style & WS_VISIBLE) DPRINTF(" WS_VISIBLE");
897 if(style & WS_DISABLED) DPRINTF(" WS_DISABLED");
898 if(style & WS_CLIPSIBLINGS) DPRINTF(" WS_CLIPSIBLINGS");
899 if(style & WS_CLIPCHILDREN) DPRINTF(" WS_CLIPCHILDREN");
900 if(style & WS_MAXIMIZE) DPRINTF(" WS_MAXIMIZE");
901 if((style & WS_CAPTION) == WS_CAPTION) DPRINTF(" WS_CAPTION");
902 else
904 if(style & WS_BORDER) DPRINTF(" WS_BORDER");
905 if(style & WS_DLGFRAME) DPRINTF(" WS_DLGFRAME");
907 if(style & WS_VSCROLL) DPRINTF(" WS_VSCROLL");
908 if(style & WS_HSCROLL) DPRINTF(" WS_HSCROLL");
909 if(style & WS_SYSMENU) DPRINTF(" WS_SYSMENU");
910 if(style & WS_THICKFRAME) DPRINTF(" WS_THICKFRAME");
911 if(style & WS_GROUP) DPRINTF(" WS_GROUP");
912 if(style & WS_TABSTOP) DPRINTF(" WS_TABSTOP");
913 if(style & WS_MINIMIZEBOX) DPRINTF(" WS_MINIMIZEBOX");
914 if(style & WS_MAXIMIZEBOX) DPRINTF(" WS_MAXIMIZEBOX");
916 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
917 #define DUMPED_STYLES \
918 (WS_POPUP | \
919 WS_CHILD | \
920 WS_MINIMIZE | \
921 WS_VISIBLE | \
922 WS_DISABLED | \
923 WS_CLIPSIBLINGS | \
924 WS_CLIPCHILDREN | \
925 WS_MAXIMIZE | \
926 WS_BORDER | \
927 WS_DLGFRAME | \
928 WS_VSCROLL | \
929 WS_HSCROLL | \
930 WS_SYSMENU | \
931 WS_THICKFRAME | \
932 WS_GROUP | \
933 WS_TABSTOP | \
934 WS_MINIMIZEBOX | \
935 WS_MAXIMIZEBOX)
937 if(style & ~DUMPED_STYLES) DPRINTF(" %08lx", style & ~DUMPED_STYLES);
938 DPRINTF("\n");
939 #undef DUMPED_STYLES
941 TRACE( "exstyle:" );
942 if(exstyle & WS_EX_DLGMODALFRAME) DPRINTF(" WS_EX_DLGMODALFRAME");
943 if(exstyle & WS_EX_DRAGDETECT) DPRINTF(" WS_EX_DRAGDETECT");
944 if(exstyle & WS_EX_NOPARENTNOTIFY) DPRINTF(" WS_EX_NOPARENTNOTIFY");
945 if(exstyle & WS_EX_TOPMOST) DPRINTF(" WS_EX_TOPMOST");
946 if(exstyle & WS_EX_ACCEPTFILES) DPRINTF(" WS_EX_ACCEPTFILES");
947 if(exstyle & WS_EX_TRANSPARENT) DPRINTF(" WS_EX_TRANSPARENT");
948 if(exstyle & WS_EX_MDICHILD) DPRINTF(" WS_EX_MDICHILD");
949 if(exstyle & WS_EX_TOOLWINDOW) DPRINTF(" WS_EX_TOOLWINDOW");
950 if(exstyle & WS_EX_WINDOWEDGE) DPRINTF(" WS_EX_WINDOWEDGE");
951 if(exstyle & WS_EX_CLIENTEDGE) DPRINTF(" WS_EX_CLIENTEDGE");
952 if(exstyle & WS_EX_CONTEXTHELP) DPRINTF(" WS_EX_CONTEXTHELP");
953 if(exstyle & WS_EX_RIGHT) DPRINTF(" WS_EX_RIGHT");
954 if(exstyle & WS_EX_RTLREADING) DPRINTF(" WS_EX_RTLREADING");
955 if(exstyle & WS_EX_LEFTSCROLLBAR) DPRINTF(" WS_EX_LEFTSCROLLBAR");
956 if(exstyle & WS_EX_CONTROLPARENT) DPRINTF(" WS_EX_CONTROLPARENT");
957 if(exstyle & WS_EX_STATICEDGE) DPRINTF(" WS_EX_STATICEDGE");
958 if(exstyle & WS_EX_APPWINDOW) DPRINTF(" WS_EX_APPWINDOW");
959 if(exstyle & WS_EX_LAYERED) DPRINTF(" WS_EX_LAYERED");
961 #define DUMPED_EX_STYLES \
962 (WS_EX_DLGMODALFRAME | \
963 WS_EX_DRAGDETECT | \
964 WS_EX_NOPARENTNOTIFY | \
965 WS_EX_TOPMOST | \
966 WS_EX_ACCEPTFILES | \
967 WS_EX_TRANSPARENT | \
968 WS_EX_MDICHILD | \
969 WS_EX_TOOLWINDOW | \
970 WS_EX_WINDOWEDGE | \
971 WS_EX_CLIENTEDGE | \
972 WS_EX_CONTEXTHELP | \
973 WS_EX_RIGHT | \
974 WS_EX_RTLREADING | \
975 WS_EX_LEFTSCROLLBAR | \
976 WS_EX_CONTROLPARENT | \
977 WS_EX_STATICEDGE | \
978 WS_EX_APPWINDOW | \
979 WS_EX_LAYERED)
981 if(exstyle & ~DUMPED_EX_STYLES) DPRINTF(" %08lx", exstyle & ~DUMPED_EX_STYLES);
982 DPRINTF("\n");
983 #undef DUMPED_EX_STYLES
987 /***********************************************************************
988 * WIN_CreateWindowEx
990 * Implementation of CreateWindowEx().
992 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
993 WINDOWPROCTYPE type )
995 INT sw = SW_SHOW;
996 struct tagCLASS *classPtr;
997 WND *wndPtr;
998 HWND hwnd, parent, owner;
999 INT wndExtra;
1000 DWORD clsStyle;
1001 WNDPROC winproc;
1002 DCE *dce;
1003 BOOL unicode = (type == WIN_PROC_32W);
1005 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%04x menu=%04x inst=%08x params=%p\n",
1006 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1007 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
1008 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1009 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1011 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1013 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1014 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1016 /* Find the parent window */
1018 parent = GetDesktopWindow();
1019 owner = 0;
1020 if (cs->hwndParent)
1022 /* Make sure parent is valid */
1023 if (!IsWindow( cs->hwndParent ))
1025 WARN("Bad parent %04x\n", cs->hwndParent );
1026 return 0;
1028 if (cs->style & WS_CHILD) parent = WIN_GetFullHandle(cs->hwndParent);
1029 else owner = GetAncestor( cs->hwndParent, GA_ROOT );
1031 else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP))
1033 WARN("No parent for child window\n" );
1034 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1037 /* Find the window class */
1038 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
1039 &wndExtra, &winproc, &clsStyle, &dce )))
1041 WARN("Bad class '%s'\n", cs->lpszClass );
1042 return 0;
1045 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1047 /* Correct the window style - stage 1
1049 * These are patches that appear to affect both the style loaded into the
1050 * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
1052 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1053 * why does the user get to set it?
1056 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1057 * tested for WS_POPUP
1059 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1060 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1061 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1062 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1063 else
1064 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1066 /* Create the window structure */
1068 if (!(wndPtr = create_window_handle( parent, owner, classAtom,
1069 sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
1071 TRACE("out of memory\n" );
1072 return 0;
1074 hwnd = wndPtr->hwndSelf;
1076 /* Fill the window structure */
1078 wndPtr->tid = GetCurrentThreadId();
1079 wndPtr->owner = owner;
1080 wndPtr->parent = parent;
1081 wndPtr->class = classPtr;
1082 wndPtr->winproc = winproc;
1083 wndPtr->hInstance = cs->hInstance;
1084 wndPtr->text = NULL;
1085 wndPtr->hmemTaskQ = InitThreadInput16( 0, 0 );
1086 wndPtr->hrgnUpdate = 0;
1087 wndPtr->hrgnWnd = 0;
1088 wndPtr->hwndLastActive = hwnd;
1089 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1090 wndPtr->dwExStyle = cs->dwExStyle;
1091 wndPtr->clsStyle = clsStyle;
1092 wndPtr->wIDmenu = 0;
1093 wndPtr->helpContext = 0;
1094 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1095 wndPtr->pVScroll = NULL;
1096 wndPtr->pHScroll = NULL;
1097 wndPtr->userdata = 0;
1098 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU)
1099 ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1100 wndPtr->cbWndExtra = wndExtra;
1102 if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
1104 /* Correct the window style - stage 2 */
1106 if (!(cs->style & WS_CHILD))
1108 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1109 if (!(cs->style & WS_POPUP))
1111 wndPtr->dwStyle |= WS_CAPTION;
1112 wndPtr->flags |= WIN_NEED_SIZE;
1115 SERVER_START_REQ( set_window_info )
1117 req->handle = hwnd;
1118 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1119 req->style = wndPtr->dwStyle;
1120 req->ex_style = wndPtr->dwExStyle;
1121 req->instance = (void *)wndPtr->hInstance;
1122 wine_server_call( req );
1124 SERVER_END_REQ;
1126 /* Get class or window DC if needed */
1128 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1129 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
1130 else wndPtr->dce = NULL;
1132 /* Set the window menu */
1134 if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
1136 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1137 else
1139 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1140 if (menuName)
1142 if (HIWORD(cs->hInstance))
1143 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1144 else
1145 cs->hMenu = LoadMenu16(cs->hInstance,menuName);
1147 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1151 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1152 WIN_ReleaseWndPtr( wndPtr );
1154 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1156 WIN_DestroyWindow( hwnd );
1157 return 0;
1160 /* Notify the parent window only */
1162 send_parent_notify( hwnd, WM_CREATE );
1163 if (!IsWindow( hwnd )) return 0;
1165 if (cs->style & WS_VISIBLE)
1167 /* in case WS_VISIBLE got set in the meantime */
1168 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1169 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1170 WIN_ReleasePtr( wndPtr );
1171 ShowWindow( hwnd, sw );
1174 /* Call WH_SHELL hook */
1176 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1177 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
1179 TRACE("created window %04x\n", hwnd);
1180 return hwnd;
1184 /***********************************************************************
1185 * CreateWindow (USER.41)
1187 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1188 DWORD style, INT16 x, INT16 y, INT16 width,
1189 INT16 height, HWND16 parent, HMENU16 menu,
1190 HINSTANCE16 instance, LPVOID data )
1192 return CreateWindowEx16( 0, className, windowName, style,
1193 x, y, width, height, parent, menu, instance, data );
1197 /***********************************************************************
1198 * CreateWindowEx (USER.452)
1200 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1201 LPCSTR windowName, DWORD style, INT16 x,
1202 INT16 y, INT16 width, INT16 height,
1203 HWND16 parent, HMENU16 menu,
1204 HINSTANCE16 instance, LPVOID data )
1206 ATOM classAtom;
1207 CREATESTRUCTA cs;
1208 char buffer[256];
1210 /* Find the class atom */
1212 if (HIWORD(className))
1214 if (!(classAtom = GlobalFindAtomA( className )))
1216 ERR( "bad class name %s\n", debugstr_a(className) );
1217 return 0;
1220 else
1222 classAtom = LOWORD(className);
1223 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1225 ERR( "bad atom %x\n", classAtom);
1226 return 0;
1228 className = buffer;
1231 /* Fix the coordinates */
1233 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1234 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1235 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1236 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1238 /* Create the window */
1240 cs.lpCreateParams = data;
1241 cs.hInstance = (HINSTANCE)instance;
1242 cs.hMenu = (HMENU)menu;
1243 cs.hwndParent = WIN_Handle32( parent );
1244 cs.style = style;
1245 cs.lpszName = windowName;
1246 cs.lpszClass = className;
1247 cs.dwExStyle = exStyle;
1249 return WIN_Handle16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1253 /***********************************************************************
1254 * CreateWindowExA (USER32.@)
1256 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1257 LPCSTR windowName, DWORD style, INT x,
1258 INT y, INT width, INT height,
1259 HWND parent, HMENU menu,
1260 HINSTANCE instance, LPVOID data )
1262 ATOM classAtom;
1263 CREATESTRUCTA cs;
1264 char buffer[256];
1266 if(!instance)
1267 instance=GetModuleHandleA(NULL);
1269 if(exStyle & WS_EX_MDICHILD)
1270 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1272 /* Find the class atom */
1274 if (HIWORD(className))
1276 if (!(classAtom = GlobalFindAtomA( className )))
1278 ERR( "bad class name %s\n", debugstr_a(className) );
1279 return 0;
1282 else
1284 classAtom = LOWORD(className);
1285 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1287 ERR( "bad atom %x\n", classAtom);
1288 return 0;
1290 className = buffer;
1293 /* Create the window */
1295 cs.lpCreateParams = data;
1296 cs.hInstance = instance;
1297 cs.hMenu = menu;
1298 cs.hwndParent = parent;
1299 cs.x = x;
1300 cs.y = y;
1301 cs.cx = width;
1302 cs.cy = height;
1303 cs.style = style;
1304 cs.lpszName = windowName;
1305 cs.lpszClass = className;
1306 cs.dwExStyle = exStyle;
1308 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1312 /***********************************************************************
1313 * CreateWindowExW (USER32.@)
1315 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1316 LPCWSTR windowName, DWORD style, INT x,
1317 INT y, INT width, INT height,
1318 HWND parent, HMENU menu,
1319 HINSTANCE instance, LPVOID data )
1321 ATOM classAtom;
1322 CREATESTRUCTW cs;
1323 WCHAR buffer[256];
1325 if(!instance)
1326 instance=GetModuleHandleA(NULL);
1328 if(exStyle & WS_EX_MDICHILD)
1329 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1331 /* Find the class atom */
1333 if (HIWORD(className))
1335 if (!(classAtom = GlobalFindAtomW( className )))
1337 ERR( "bad class name %s\n", debugstr_w(className) );
1338 return 0;
1341 else
1343 classAtom = LOWORD(className);
1344 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1346 ERR( "bad atom %x\n", classAtom);
1347 return 0;
1349 className = buffer;
1352 /* Create the window */
1354 cs.lpCreateParams = data;
1355 cs.hInstance = instance;
1356 cs.hMenu = menu;
1357 cs.hwndParent = parent;
1358 cs.x = x;
1359 cs.y = y;
1360 cs.cx = width;
1361 cs.cy = height;
1362 cs.style = style;
1363 cs.lpszName = windowName;
1364 cs.lpszClass = className;
1365 cs.dwExStyle = exStyle;
1367 /* Note: we rely on the fact that CREATESTRUCTA and */
1368 /* CREATESTRUCTW have the same layout. */
1369 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1373 /***********************************************************************
1374 * WIN_SendDestroyMsg
1376 static void WIN_SendDestroyMsg( HWND hwnd )
1378 if( CARET_GetHwnd() == hwnd) DestroyCaret();
1379 if (USER_Driver.pResetSelectionOwner)
1380 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1383 * Send the WM_DESTROY to the window.
1385 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1388 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1389 * make sure that the window still exists when we come back.
1391 if (IsWindow(hwnd))
1393 HWND* pWndArray;
1394 int i;
1396 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1398 /* start from the end (FIXME: is this needed?) */
1399 for (i = 0; pWndArray[i]; i++) ;
1401 while (--i >= 0)
1403 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1405 HeapFree( GetProcessHeap(), 0, pWndArray );
1407 else
1408 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1412 /***********************************************************************
1413 * DestroyWindow (USER32.@)
1415 BOOL WINAPI DestroyWindow( HWND hwnd )
1417 BOOL is_child;
1418 HWND h;
1420 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1422 SetLastError( ERROR_ACCESS_DENIED );
1423 return FALSE;
1426 TRACE("(%04x)\n", hwnd);
1428 /* Look whether the focus is within the tree of windows we will
1429 * be destroying.
1431 h = GetFocus();
1432 if (h == hwnd || IsChild( hwnd, h ))
1434 HWND parent = GetAncestor( hwnd, GA_PARENT );
1435 if (parent == GetDesktopWindow()) parent = 0;
1436 SetFocus( parent );
1439 /* Call hooks */
1441 if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
1443 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1445 if (is_child)
1447 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1448 send_parent_notify( hwnd, WM_DESTROY );
1450 else if (!GetWindow( hwnd, GW_OWNER ))
1452 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
1453 /* FIXME: clean up palette - see "Internals" p.352 */
1456 if (!IsWindow(hwnd)) return TRUE;
1458 if (USER_Driver.pResetSelectionOwner)
1459 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1461 /* Hide the window */
1463 ShowWindow( hwnd, SW_HIDE );
1464 if (!IsWindow(hwnd)) return TRUE;
1466 /* Recursively destroy owned windows */
1468 if (!is_child)
1470 HWND owner;
1472 for (;;)
1474 int i, got_one = 0;
1475 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1476 if (list)
1478 for (i = 0; list[i]; i++)
1480 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1481 if (WIN_IsCurrentThread( list[i] ))
1483 DestroyWindow( list[i] );
1484 got_one = 1;
1485 continue;
1487 WIN_SetOwner( list[i], 0 );
1489 HeapFree( GetProcessHeap(), 0, list );
1491 if (!got_one) break;
1494 WINPOS_ActivateOtherWindow( hwnd );
1496 if ((owner = GetWindow( hwnd, GW_OWNER )))
1498 WND *ptr = WIN_FindWndPtr( owner );
1499 if (ptr)
1501 if (ptr->hwndLastActive == hwnd) ptr->hwndLastActive = owner;
1502 WIN_ReleaseWndPtr( ptr );
1507 /* Send destroy messages */
1509 WIN_SendDestroyMsg( hwnd );
1510 if (!IsWindow( hwnd )) return TRUE;
1512 /* Unlink now so we won't bother with the children later on */
1514 WIN_UnlinkWindow( hwnd );
1516 /* Destroy the window storage */
1518 WIN_DestroyWindow( hwnd );
1519 return TRUE;
1523 /***********************************************************************
1524 * CloseWindow (USER32.@)
1526 BOOL WINAPI CloseWindow( HWND hwnd )
1528 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1529 ShowWindow( hwnd, SW_MINIMIZE );
1530 return TRUE;
1534 /***********************************************************************
1535 * OpenIcon (USER32.@)
1537 BOOL WINAPI OpenIcon( HWND hwnd )
1539 if (!IsIconic( hwnd )) return FALSE;
1540 ShowWindow( hwnd, SW_SHOWNORMAL );
1541 return TRUE;
1545 /***********************************************************************
1546 * WIN_FindWindow
1548 * Implementation of FindWindow() and FindWindowEx().
1550 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1552 HWND *list = NULL;
1553 HWND retvalue = 0;
1554 int i = 0, len = 0;
1555 WCHAR *buffer = NULL;
1557 if (!parent) parent = GetDesktopWindow();
1558 if (title)
1560 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1561 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1564 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1566 if (child)
1568 child = WIN_GetFullHandle( child );
1569 while (list[i] && list[i] != child) i++;
1570 if (!list[i]) goto done;
1571 i++; /* start from next window */
1574 if (title)
1576 while (list[i])
1578 if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1579 i++;
1582 retvalue = list[i];
1584 done:
1585 if (list) HeapFree( GetProcessHeap(), 0, list );
1586 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1587 return retvalue;
1592 /***********************************************************************
1593 * FindWindowA (USER32.@)
1595 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1597 HWND ret = FindWindowExA( 0, 0, className, title );
1598 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1599 return ret;
1603 /***********************************************************************
1604 * FindWindowExA (USER32.@)
1606 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1607 LPCSTR className, LPCSTR title )
1609 ATOM atom = 0;
1610 LPWSTR buffer;
1611 HWND hwnd;
1612 INT len;
1614 if (className)
1616 /* If the atom doesn't exist, then no class */
1617 /* with this name exists either. */
1618 if (!(atom = GlobalFindAtomA( className )))
1620 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1621 return 0;
1624 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1626 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1627 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1628 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1629 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1630 HeapFree( GetProcessHeap(), 0, buffer );
1631 return hwnd;
1635 /***********************************************************************
1636 * FindWindowExW (USER32.@)
1638 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1639 LPCWSTR className, LPCWSTR title )
1641 ATOM atom = 0;
1643 if (className)
1645 /* If the atom doesn't exist, then no class */
1646 /* with this name exists either. */
1647 if (!(atom = GlobalFindAtomW( className )))
1649 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1650 return 0;
1653 return WIN_FindWindow( parent, child, atom, title );
1657 /***********************************************************************
1658 * FindWindowW (USER32.@)
1660 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1662 return FindWindowExW( 0, 0, className, title );
1666 /**********************************************************************
1667 * GetDesktopWindow (USER32.@)
1669 HWND WINAPI GetDesktopWindow(void)
1671 if (pWndDesktop) return pWndDesktop->hwndSelf;
1672 ERR( "Wine init error: either you're trying to use an invalid native USER.EXE config, or some graphics/GUI libraries or DLLs didn't initialize properly. Aborting.\n" );
1673 ExitProcess(1);
1674 return 0;
1678 /*******************************************************************
1679 * EnableWindow (USER32.@)
1681 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1683 WND *wndPtr;
1684 BOOL retvalue;
1685 LONG style;
1686 HWND full_handle;
1688 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1689 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1691 hwnd = full_handle;
1693 TRACE("( %x, %d )\n", hwnd, enable);
1695 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1696 style = wndPtr->dwStyle;
1697 retvalue = ((style & WS_DISABLED) != 0);
1698 WIN_ReleasePtr( wndPtr );
1700 if (enable && retvalue)
1702 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1703 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1705 else if (!enable && !retvalue)
1707 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1709 WIN_SetStyle( hwnd, style | WS_DISABLED );
1711 if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
1712 SetFocus( 0 ); /* A disabled window can't have the focus */
1714 if (hwnd == GetCapture() || IsChild(hwnd, GetCapture()))
1715 ReleaseCapture(); /* A disabled window can't capture the mouse */
1717 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1719 return retvalue;
1723 /***********************************************************************
1724 * IsWindowEnabled (USER32.@)
1726 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1728 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1732 /***********************************************************************
1733 * IsWindowUnicode (USER32.@)
1735 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1737 WND * wndPtr;
1738 BOOL retvalue;
1740 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1741 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1742 WIN_ReleaseWndPtr(wndPtr);
1743 return retvalue;
1747 /**********************************************************************
1748 * GetWindowWord (USER32.@)
1750 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1752 if (offset >= 0)
1754 WORD retvalue = 0;
1755 WND *wndPtr = WIN_GetPtr( hwnd );
1756 if (!wndPtr)
1758 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1759 return 0;
1761 if (wndPtr == WND_OTHER_PROCESS)
1763 if (IsWindow( hwnd ))
1764 FIXME( "(%d) not supported yet on other process window %x\n", offset, hwnd );
1765 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1766 return 0;
1768 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1770 WARN("Invalid offset %d\n", offset );
1771 SetLastError( ERROR_INVALID_INDEX );
1773 else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1774 WIN_ReleasePtr( wndPtr );
1775 return retvalue;
1778 switch(offset)
1780 case GWL_HWNDPARENT:
1781 return GetWindowLongW( hwnd, offset );
1782 case GWL_ID:
1783 case GWL_HINSTANCE:
1785 LONG ret = GetWindowLongW( hwnd, offset );
1786 if (HIWORD(ret))
1787 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1788 return LOWORD(ret);
1790 default:
1791 WARN("Invalid offset %d\n", offset );
1792 return 0;
1797 /**********************************************************************
1798 * SetWindowWord (USER32.@)
1800 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1802 WORD *ptr, retval;
1803 WND * wndPtr;
1805 switch(offset)
1807 case GWL_ID:
1808 case GWL_HINSTANCE:
1809 case GWL_HWNDPARENT:
1810 return SetWindowLongW( hwnd, offset, (UINT)newval );
1811 default:
1812 if (offset < 0)
1814 WARN("Invalid offset %d\n", offset );
1815 SetLastError( ERROR_INVALID_INDEX );
1816 return 0;
1820 wndPtr = WIN_GetPtr( hwnd );
1821 if (wndPtr == WND_OTHER_PROCESS)
1823 if (IsWindow(hwnd))
1824 FIXME( "set %d <- %x not supported yet on other process window %x\n",
1825 offset, newval, hwnd );
1826 wndPtr = NULL;
1828 if (!wndPtr)
1830 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1831 return 0;
1834 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1836 WARN("Invalid offset %d\n", offset );
1837 WIN_ReleasePtr(wndPtr);
1838 SetLastError( ERROR_INVALID_INDEX );
1839 return 0;
1841 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1842 retval = *ptr;
1843 *ptr = newval;
1844 WIN_ReleasePtr(wndPtr);
1845 return retval;
1849 /**********************************************************************
1850 * WIN_GetWindowLong
1852 * Helper function for GetWindowLong().
1854 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1856 LONG retvalue = 0;
1857 WND *wndPtr;
1859 if (offset == GWL_HWNDPARENT) return (LONG)GetParent( hwnd );
1861 if (!(wndPtr = WIN_GetPtr( hwnd )))
1863 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1864 return 0;
1867 if (wndPtr == WND_OTHER_PROCESS)
1869 if (offset >= 0)
1871 if (IsWindow(hwnd))
1872 FIXME( "(%d) not supported on other process window %x\n", offset, hwnd );
1873 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1874 return 0;
1876 if (offset == GWL_WNDPROC)
1878 SetLastError( ERROR_ACCESS_DENIED );
1879 return 0;
1881 SERVER_START_REQ( set_window_info )
1883 req->handle = hwnd;
1884 req->flags = 0; /* don't set anything, just retrieve */
1885 if (!wine_server_call_err( req ))
1887 switch(offset)
1889 case GWL_STYLE: retvalue = reply->old_style; break;
1890 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1891 case GWL_ID: retvalue = reply->old_id; break;
1892 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1893 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1894 default:
1895 SetLastError( ERROR_INVALID_INDEX );
1896 break;
1900 SERVER_END_REQ;
1901 return retvalue;
1904 /* now we have a valid wndPtr */
1906 if (offset >= 0)
1908 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1911 * Some programs try to access last element from 16 bit
1912 * code using illegal offset value. Hopefully this is
1913 * what those programs really expect.
1915 if (type == WIN_PROC_16 &&
1916 wndPtr->cbWndExtra >= 4 &&
1917 offset == wndPtr->cbWndExtra - sizeof(WORD))
1919 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1921 ERR( "- replaced invalid offset %d with %d\n",
1922 offset, offset2 );
1924 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1925 WIN_ReleasePtr( wndPtr );
1926 return retvalue;
1928 WARN("Invalid offset %d\n", offset );
1929 WIN_ReleasePtr( wndPtr );
1930 SetLastError( ERROR_INVALID_INDEX );
1931 return 0;
1933 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1934 /* Special case for dialog window procedure */
1935 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1936 retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1937 WIN_ReleasePtr( wndPtr );
1938 return retvalue;
1941 switch(offset)
1943 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
1944 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1945 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1946 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
1947 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1948 case GWL_HINSTANCE: retvalue = wndPtr->hInstance; break;
1949 default:
1950 WARN("Unknown offset %d\n", offset );
1951 SetLastError( ERROR_INVALID_INDEX );
1952 break;
1954 WIN_ReleasePtr(wndPtr);
1955 return retvalue;
1959 /**********************************************************************
1960 * WIN_SetWindowLong
1962 * Helper function for SetWindowLong().
1964 * 0 is the failure code. However, in the case of failure SetLastError
1965 * must be set to distinguish between a 0 return value and a failure.
1967 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1968 WINDOWPROCTYPE type )
1970 LONG retval = 0;
1971 WND *wndPtr;
1973 TRACE( "%x %d %lx %x\n", hwnd, offset, newval, type );
1975 if (!WIN_IsCurrentProcess( hwnd ))
1977 if (offset == GWL_WNDPROC)
1979 SetLastError( ERROR_ACCESS_DENIED );
1980 return 0;
1982 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1985 wndPtr = WIN_GetPtr( hwnd );
1987 if (offset >= 0)
1989 LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1990 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1992 WARN("Invalid offset %d\n", offset );
1993 WIN_ReleasePtr( wndPtr );
1994 SetLastError( ERROR_INVALID_INDEX );
1995 return 0;
1997 /* Special case for dialog window procedure */
1998 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2000 retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
2001 WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
2002 type, WIN_PROC_WINDOW );
2003 WIN_ReleasePtr( wndPtr );
2004 return retval;
2006 retval = *ptr;
2007 *ptr = newval;
2008 WIN_ReleasePtr( wndPtr );
2010 else
2012 STYLESTRUCT style;
2013 BOOL ok;
2015 /* first some special cases */
2016 switch( offset )
2018 case GWL_STYLE:
2019 case GWL_EXSTYLE:
2020 style.styleOld = wndPtr->dwStyle;
2021 style.styleNew = newval;
2022 WIN_ReleasePtr( wndPtr );
2023 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2024 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2025 newval = style.styleNew;
2026 break;
2027 case GWL_HWNDPARENT:
2028 WIN_ReleasePtr( wndPtr );
2029 return (LONG)SetParent( hwnd, (HWND)newval );
2030 case GWL_WNDPROC:
2031 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2032 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
2033 type, WIN_PROC_WINDOW );
2034 WIN_ReleasePtr( wndPtr );
2035 return retval;
2036 case GWL_ID:
2037 case GWL_HINSTANCE:
2038 case GWL_USERDATA:
2039 break;
2040 default:
2041 WIN_ReleasePtr( wndPtr );
2042 WARN("Invalid offset %d\n", offset );
2043 SetLastError( ERROR_INVALID_INDEX );
2044 return 0;
2047 SERVER_START_REQ( set_window_info )
2049 req->handle = hwnd;
2050 switch(offset)
2052 case GWL_STYLE:
2053 req->flags = SET_WIN_STYLE;
2054 req->style = newval;
2055 break;
2056 case GWL_EXSTYLE:
2057 req->flags = SET_WIN_EXSTYLE;
2058 req->ex_style = newval;
2059 break;
2060 case GWL_ID:
2061 req->flags = SET_WIN_ID;
2062 req->id = newval;
2063 break;
2064 case GWL_HINSTANCE:
2065 req->flags = SET_WIN_INSTANCE;
2066 req->instance = (void *)newval;
2067 break;
2068 case GWL_USERDATA:
2069 req->flags = SET_WIN_USERDATA;
2070 req->user_data = (void *)newval;
2071 break;
2073 if ((ok = !wine_server_call_err( req )))
2075 switch(offset)
2077 case GWL_STYLE:
2078 wndPtr->dwStyle = newval;
2079 retval = reply->old_style;
2080 break;
2081 case GWL_EXSTYLE:
2082 wndPtr->dwExStyle = newval;
2083 retval = reply->old_ex_style;
2084 break;
2085 case GWL_ID:
2086 wndPtr->wIDmenu = newval;
2087 retval = reply->old_id;
2088 break;
2089 case GWL_HINSTANCE:
2090 wndPtr->hInstance = newval;
2091 retval = (HINSTANCE)reply->old_instance;
2092 break;
2093 case GWL_USERDATA:
2094 wndPtr->userdata = newval;
2095 retval = (ULONG_PTR)reply->old_user_data;
2096 break;
2100 SERVER_END_REQ;
2101 WIN_ReleasePtr( wndPtr );
2103 if (!ok) return 0;
2105 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2106 USER_Driver.pSetWindowStyle( hwnd, retval );
2108 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2109 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2112 return retval;
2116 /**********************************************************************
2117 * GetWindowLong (USER.135)
2119 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2121 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2125 /**********************************************************************
2126 * GetWindowLongA (USER32.@)
2128 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2130 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2134 /**********************************************************************
2135 * GetWindowLongW (USER32.@)
2137 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2139 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2143 /**********************************************************************
2144 * SetWindowLong (USER.136)
2146 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2148 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2152 /**********************************************************************
2153 * SetWindowLongA (USER32.@)
2155 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2157 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2161 /**********************************************************************
2162 * SetWindowLongW (USER32.@) Set window attribute
2164 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2165 * value in a window's extra memory.
2167 * The _hwnd_ parameter specifies the window. is the handle to a
2168 * window that has extra memory. The _newval_ parameter contains the
2169 * new attribute or extra memory value. If positive, the _offset_
2170 * parameter is the byte-addressed location in the window's extra
2171 * memory to set. If negative, _offset_ specifies the window
2172 * attribute to set, and should be one of the following values:
2174 * GWL_EXSTYLE The window's extended window style
2176 * GWL_STYLE The window's window style.
2178 * GWL_WNDPROC Pointer to the window's window procedure.
2180 * GWL_HINSTANCE The window's pplication instance handle.
2182 * GWL_ID The window's identifier.
2184 * GWL_USERDATA The window's user-specified data.
2186 * If the window is a dialog box, the _offset_ parameter can be one of
2187 * the following values:
2189 * DWL_DLGPROC The address of the window's dialog box procedure.
2191 * DWL_MSGRESULT The return value of a message
2192 * that the dialog box procedure processed.
2194 * DWL_USER Application specific information.
2196 * RETURNS
2198 * If successful, returns the previous value located at _offset_. Otherwise,
2199 * returns 0.
2201 * NOTES
2203 * Extra memory for a window class is specified by a nonzero cbWndExtra
2204 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2205 * time of class creation.
2207 * Using GWL_WNDPROC to set a new window procedure effectively creates
2208 * a window subclass. Use CallWindowProc() in the new windows procedure
2209 * to pass messages to the superclass's window procedure.
2211 * The user data is reserved for use by the application which created
2212 * the window.
2214 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2215 * instead, call the EnableWindow() function to change the window's
2216 * disabled state.
2218 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2219 * SetParent() instead.
2221 * Win95:
2222 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2223 * it sends WM_STYLECHANGING before changing the settings
2224 * and WM_STYLECHANGED afterwards.
2225 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2227 LONG WINAPI SetWindowLongW(
2228 HWND hwnd, /* [in] window to alter */
2229 INT offset, /* [in] offset, in bytes, of location to alter */
2230 LONG newval /* [in] new value of location */
2232 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2236 /*******************************************************************
2237 * GetWindowTextA (USER32.@)
2239 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2241 WCHAR *buffer;
2243 if (WIN_IsCurrentProcess( hwnd ))
2244 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2246 /* when window belongs to other process, don't send a message */
2247 if (nMaxCount <= 0) return 0;
2248 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2249 get_server_window_text( hwnd, buffer, nMaxCount );
2250 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2251 lpString[nMaxCount-1] = 0;
2252 HeapFree( GetProcessHeap(), 0, buffer );
2253 return strlen(lpString);
2257 /*******************************************************************
2258 * InternalGetWindowText (USER32.@)
2260 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2262 WND *win;
2264 if (nMaxCount <= 0) return 0;
2265 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2266 if (win != WND_OTHER_PROCESS)
2268 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2269 else lpString[0] = 0;
2270 WIN_ReleasePtr( win );
2272 else
2274 get_server_window_text( hwnd, lpString, nMaxCount );
2276 return strlenW(lpString);
2280 /*******************************************************************
2281 * GetWindowTextW (USER32.@)
2283 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2285 if (WIN_IsCurrentProcess( hwnd ))
2286 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2288 /* when window belongs to other process, don't send a message */
2289 if (nMaxCount <= 0) return 0;
2290 get_server_window_text( hwnd, lpString, nMaxCount );
2291 return strlenW(lpString);
2295 /*******************************************************************
2296 * SetWindowText (USER32.@)
2297 * SetWindowTextA (USER32.@)
2299 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2301 if (!WIN_IsCurrentProcess( hwnd ))
2303 FIXME( "cannot set text %s of other process window %x\n", debugstr_a(lpString), hwnd );
2304 SetLastError( ERROR_ACCESS_DENIED );
2305 return FALSE;
2307 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2311 /*******************************************************************
2312 * SetWindowTextW (USER32.@)
2314 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2316 if (!WIN_IsCurrentProcess( hwnd ))
2318 FIXME( "cannot set text %s of other process window %x\n", debugstr_w(lpString), hwnd );
2319 SetLastError( ERROR_ACCESS_DENIED );
2320 return FALSE;
2322 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2326 /*******************************************************************
2327 * GetWindowTextLengthA (USER32.@)
2329 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2331 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2334 /*******************************************************************
2335 * GetWindowTextLengthW (USER32.@)
2337 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2339 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2343 /*******************************************************************
2344 * IsWindow (USER32.@)
2346 BOOL WINAPI IsWindow( HWND hwnd )
2348 WND *ptr;
2349 BOOL ret;
2351 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2353 if (ptr != WND_OTHER_PROCESS)
2355 WIN_ReleasePtr( ptr );
2356 return TRUE;
2359 /* check other processes */
2360 SERVER_START_REQ( get_window_info )
2362 req->handle = hwnd;
2363 ret = !wine_server_call_err( req );
2365 SERVER_END_REQ;
2366 return ret;
2370 /***********************************************************************
2371 * GetWindowThreadProcessId (USER32.@)
2373 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2375 WND *ptr;
2376 DWORD tid = 0;
2378 if (!(ptr = WIN_GetPtr( hwnd )))
2380 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2381 return 0;
2384 if (ptr != WND_OTHER_PROCESS)
2386 /* got a valid window */
2387 tid = ptr->tid;
2388 if (process) *process = GetCurrentProcessId();
2389 WIN_ReleasePtr( ptr );
2390 return tid;
2393 /* check other processes */
2394 SERVER_START_REQ( get_window_info )
2396 req->handle = hwnd;
2397 if (!wine_server_call_err( req ))
2399 tid = (DWORD)reply->tid;
2400 if (process) *process = (DWORD)reply->pid;
2403 SERVER_END_REQ;
2404 return tid;
2408 /*****************************************************************
2409 * GetParent (USER32.@)
2411 HWND WINAPI GetParent( HWND hwnd )
2413 WND *wndPtr;
2414 HWND retvalue = 0;
2416 if (!(wndPtr = WIN_GetPtr( hwnd )))
2418 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2419 return 0;
2421 if (wndPtr == WND_OTHER_PROCESS)
2423 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2424 if (style & (WS_POPUP | WS_CHILD))
2426 SERVER_START_REQ( get_window_tree )
2428 req->handle = hwnd;
2429 if (!wine_server_call_err( req ))
2431 if (style & WS_CHILD) retvalue = reply->parent;
2432 else retvalue = reply->owner;
2435 SERVER_END_REQ;
2438 else
2440 if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2441 else if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2442 WIN_ReleasePtr( wndPtr );
2444 return retvalue;
2448 /*****************************************************************
2449 * GetAncestor (USER32.@)
2451 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2453 WND *win;
2454 HWND *list, ret = 0;
2456 if (type == GA_PARENT)
2458 if (!(win = WIN_GetPtr( hwnd )))
2460 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2461 return 0;
2463 if (win != WND_OTHER_PROCESS)
2465 ret = win->parent;
2466 WIN_ReleasePtr( win );
2468 else /* need to query the server */
2470 SERVER_START_REQ( get_window_tree )
2472 req->handle = hwnd;
2473 if (!wine_server_call_err( req )) ret = reply->parent;
2475 SERVER_END_REQ;
2477 return ret;
2480 if (!(list = WIN_ListParents( hwnd ))) return 0;
2482 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2483 else
2485 int count = 2;
2486 while (list[count]) count++;
2487 ret = list[count - 2]; /* get the one before the desktop */
2489 HeapFree( GetProcessHeap(), 0, list );
2491 if (ret && type == GA_ROOTOWNER)
2493 for (;;)
2495 HWND owner = GetWindow( ret, GW_OWNER );
2496 if (!owner) break;
2497 ret = owner;
2500 return ret;
2504 /*****************************************************************
2505 * SetParent (USER32.@)
2507 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2509 WND *wndPtr;
2510 HWND retvalue, full_handle;
2511 BOOL was_visible;
2513 if (!parent) parent = GetDesktopWindow();
2514 else parent = WIN_GetFullHandle( parent );
2516 if (!IsWindow( parent ))
2518 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2519 return 0;
2522 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2523 return SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2525 hwnd = full_handle;
2527 if (USER_Driver.pSetParent)
2528 return USER_Driver.pSetParent( hwnd, parent );
2530 /* Windows hides the window first, then shows it again
2531 * including the WM_SHOWWINDOW messages and all */
2532 was_visible = ShowWindow( hwnd, SW_HIDE );
2534 if (!IsWindow( parent )) return 0;
2535 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2537 retvalue = wndPtr->parent; /* old parent */
2538 if (parent != retvalue)
2540 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2542 if (parent != GetDesktopWindow()) /* a child window */
2544 if (!(wndPtr->dwStyle & WS_CHILD))
2546 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2547 if (menu) DestroyMenu( menu );
2551 WIN_ReleasePtr( wndPtr );
2553 /* SetParent additionally needs to make hwnd the topmost window
2554 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2555 WM_WINDOWPOSCHANGED notification messages.
2557 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2558 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2559 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2560 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2561 return retvalue;
2565 /*******************************************************************
2566 * IsChild (USER32.@)
2568 BOOL WINAPI IsChild( HWND parent, HWND child )
2570 HWND *list = WIN_ListParents( child );
2571 int i;
2572 BOOL ret;
2574 if (!list) return FALSE;
2575 parent = WIN_GetFullHandle( parent );
2576 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2577 ret = (list[i] != 0);
2578 HeapFree( GetProcessHeap(), 0, list );
2579 return ret;
2583 /***********************************************************************
2584 * IsWindowVisible (USER32.@)
2586 BOOL WINAPI IsWindowVisible( HWND hwnd )
2588 HWND *list;
2589 BOOL retval;
2590 int i;
2592 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2593 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2594 for (i = 0; list[i]; i++)
2595 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2596 retval = !list[i];
2597 HeapFree( GetProcessHeap(), 0, list );
2598 return retval;
2602 /***********************************************************************
2603 * WIN_IsWindowDrawable
2605 * hwnd is drawable when it is visible, all parents are not
2606 * minimized, and it is itself not minimized unless we are
2607 * trying to draw its default class icon.
2609 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2611 HWND *list;
2612 BOOL retval;
2613 int i;
2614 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2616 if (!(style & WS_VISIBLE)) return FALSE;
2617 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2619 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2620 for (i = 0; list[i]; i++)
2621 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2622 break;
2623 retval = !list[i];
2624 HeapFree( GetProcessHeap(), 0, list );
2625 return retval;
2629 /*******************************************************************
2630 * GetTopWindow (USER32.@)
2632 HWND WINAPI GetTopWindow( HWND hwnd )
2634 if (!hwnd) hwnd = GetDesktopWindow();
2635 return GetWindow( hwnd, GW_CHILD );
2639 /*******************************************************************
2640 * GetWindow (USER32.@)
2642 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2644 HWND retval = 0;
2646 if (rel == GW_OWNER) /* this one may be available locally */
2648 WND *wndPtr = WIN_GetPtr( hwnd );
2649 if (!wndPtr)
2651 SetLastError( ERROR_INVALID_HANDLE );
2652 return 0;
2654 if (wndPtr != WND_OTHER_PROCESS)
2656 retval = wndPtr->owner;
2657 WIN_ReleasePtr( wndPtr );
2658 return retval;
2660 /* else fall through to server call */
2663 SERVER_START_REQ( get_window_tree )
2665 req->handle = hwnd;
2666 if (!wine_server_call_err( req ))
2668 switch(rel)
2670 case GW_HWNDFIRST:
2671 retval = reply->first_sibling;
2672 break;
2673 case GW_HWNDLAST:
2674 retval = reply->last_sibling;
2675 break;
2676 case GW_HWNDNEXT:
2677 retval = reply->next_sibling;
2678 break;
2679 case GW_HWNDPREV:
2680 retval = reply->prev_sibling;
2681 break;
2682 case GW_OWNER:
2683 retval = reply->owner;
2684 break;
2685 case GW_CHILD:
2686 retval = reply->first_child;
2687 break;
2691 SERVER_END_REQ;
2692 return retval;
2696 /***********************************************************************
2697 * WIN_InternalShowOwnedPopups
2699 * Internal version of ShowOwnedPopups; Wine functions should use this
2700 * to avoid interfering with application calls to ShowOwnedPopups
2701 * and to make sure the application can't prevent showing/hiding.
2703 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2707 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2709 int count = 0;
2710 WND *pWnd;
2711 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2713 if (!win_array) return TRUE;
2716 * Show windows Lowest first, Highest last to preserve Z-Order
2718 while (win_array[count]) count++;
2719 while (--count >= 0)
2721 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2722 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2724 if (pWnd->dwStyle & WS_POPUP)
2726 if (fShow)
2728 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2729 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2732 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2734 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2735 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2738 else
2740 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2741 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2742 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2745 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2747 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2748 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2749 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2753 WIN_ReleaseWndPtr( pWnd );
2755 HeapFree( GetProcessHeap(), 0, win_array );
2757 return TRUE;
2760 /*******************************************************************
2761 * ShowOwnedPopups (USER32.@)
2763 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2765 int count = 0;
2766 WND *pWnd;
2767 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2769 if (!win_array) return TRUE;
2771 while (win_array[count]) count++;
2772 while (--count >= 0)
2774 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2775 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2777 if (pWnd->dwStyle & WS_POPUP)
2779 if (fShow)
2781 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2783 /* In Windows, ShowOwnedPopups(TRUE) generates
2784 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2785 * regardless of the state of the owner
2787 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2788 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2791 else
2793 if (IsWindowVisible(pWnd->hwndSelf))
2795 /* In Windows, ShowOwnedPopups(FALSE) generates
2796 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2797 * regardless of the state of the owner
2799 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2800 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2804 WIN_ReleaseWndPtr( pWnd );
2806 HeapFree( GetProcessHeap(), 0, win_array );
2807 return TRUE;
2811 /*******************************************************************
2812 * GetLastActivePopup (USER32.@)
2814 HWND WINAPI GetLastActivePopup( HWND hwnd )
2816 HWND retval;
2817 WND *wndPtr =WIN_FindWndPtr(hwnd);
2818 if (!wndPtr) return hwnd;
2819 retval = wndPtr->hwndLastActive;
2820 if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2821 WIN_ReleaseWndPtr(wndPtr);
2822 return retval;
2826 /*******************************************************************
2827 * WIN_ListParents
2829 * Build an array of all parents of a given window, starting with
2830 * the immediate parent. The array must be freed with HeapFree.
2831 * Returns NULL if window is a top-level window.
2833 HWND *WIN_ListParents( HWND hwnd )
2835 WND *win;
2836 HWND current, *list;
2837 int pos = 0, size = 16, count = 0;
2839 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2841 current = hwnd;
2842 for (;;)
2844 if (!(win = WIN_GetPtr( current ))) goto empty;
2845 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2846 list[pos] = win->parent;
2847 WIN_ReleasePtr( win );
2848 if (!(current = list[pos]))
2850 if (!pos) goto empty;
2851 return list;
2853 if (++pos == size - 1)
2855 /* need to grow the list */
2856 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2857 if (!new_list) goto empty;
2858 list = new_list;
2859 size += 16;
2863 /* at least one parent belongs to another process, have to query the server */
2865 for (;;)
2867 count = 0;
2868 SERVER_START_REQ( get_window_parents )
2870 req->handle = hwnd;
2871 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2872 if (!wine_server_call( req )) count = reply->count;
2874 SERVER_END_REQ;
2875 if (!count) goto empty;
2876 if (size > count)
2878 list[count] = 0;
2879 return list;
2881 HeapFree( GetProcessHeap(), 0, list );
2882 size = count + 1;
2883 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2886 empty:
2887 HeapFree( GetProcessHeap(), 0, list );
2888 return NULL;
2892 /*******************************************************************
2893 * WIN_ListChildren
2895 * Build an array of the children of a given window. The array must be
2896 * freed with HeapFree. Returns NULL when no windows are found.
2898 HWND *WIN_ListChildren( HWND hwnd )
2900 return list_window_children( hwnd, 0, 0 );
2904 /*******************************************************************
2905 * EnumWindows (USER32.@)
2907 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2909 HWND *list;
2910 BOOL ret = TRUE;
2911 int i, iWndsLocks;
2913 /* We have to build a list of all windows first, to avoid */
2914 /* unpleasant side-effects, for instance if the callback */
2915 /* function changes the Z-order of the windows. */
2917 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2919 /* Now call the callback function for every window */
2921 iWndsLocks = WIN_SuspendWndsLock();
2922 for (i = 0; list[i]; i++)
2924 /* Make sure that the window still exists */
2925 if (!IsWindow( list[i] )) continue;
2926 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2928 WIN_RestoreWndsLock(iWndsLocks);
2929 HeapFree( GetProcessHeap(), 0, list );
2930 return ret;
2934 /**********************************************************************
2935 * EnumThreadWindows (USER32.@)
2937 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2939 HWND *list;
2940 int i, iWndsLocks;
2942 if (!(list = list_window_children( GetDesktopWindow(), 0, GetCurrentThreadId() )))
2943 return TRUE ;
2945 /* Now call the callback function for every window */
2947 iWndsLocks = WIN_SuspendWndsLock();
2948 for (i = 0; list[i]; i++)
2949 if (!func( list[i], lParam )) break;
2950 WIN_RestoreWndsLock(iWndsLocks);
2951 HeapFree( GetProcessHeap(), 0, list );
2952 return TRUE;
2956 /**********************************************************************
2957 * WIN_EnumChildWindows
2959 * Helper function for EnumChildWindows().
2961 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2963 HWND *childList;
2964 BOOL ret = FALSE;
2966 for ( ; *list; list++)
2968 /* Make sure that the window still exists */
2969 if (!IsWindow( *list )) continue;
2970 /* skip owned windows */
2971 if (GetWindow( *list, GW_OWNER )) continue;
2972 /* Build children list first */
2973 childList = WIN_ListChildren( *list );
2975 ret = func( *list, lParam );
2977 if (childList)
2979 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2980 HeapFree( GetProcessHeap(), 0, childList );
2982 if (!ret) return FALSE;
2984 return TRUE;
2988 /**********************************************************************
2989 * EnumChildWindows (USER32.@)
2991 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2993 HWND *list;
2994 int iWndsLocks;
2996 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2997 iWndsLocks = WIN_SuspendWndsLock();
2998 WIN_EnumChildWindows( list, func, lParam );
2999 WIN_RestoreWndsLock(iWndsLocks);
3000 HeapFree( GetProcessHeap(), 0, list );
3001 return TRUE;
3005 /*******************************************************************
3006 * AnyPopup (USER.52)
3008 BOOL16 WINAPI AnyPopup16(void)
3010 return AnyPopup();
3014 /*******************************************************************
3015 * AnyPopup (USER32.@)
3017 BOOL WINAPI AnyPopup(void)
3019 int i;
3020 BOOL retvalue;
3021 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3023 if (!list) return FALSE;
3024 for (i = 0; list[i]; i++)
3026 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3028 retvalue = (list[i] != 0);
3029 HeapFree( GetProcessHeap(), 0, list );
3030 return retvalue;
3034 /*******************************************************************
3035 * FlashWindow (USER32.@)
3037 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3039 WND *wndPtr = WIN_FindWndPtr(hWnd);
3041 TRACE("%04x\n", hWnd);
3043 if (!wndPtr) return FALSE;
3044 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3046 if (wndPtr->dwStyle & WS_MINIMIZE)
3048 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3050 HDC hDC = GetDC(hWnd);
3052 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
3053 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3055 ReleaseDC( hWnd, hDC );
3056 wndPtr->flags |= WIN_NCACTIVATED;
3058 else
3060 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3061 wndPtr->flags &= ~WIN_NCACTIVATED;
3063 WIN_ReleaseWndPtr(wndPtr);
3064 return TRUE;
3066 else
3068 WPARAM16 wparam;
3069 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3070 else wparam = (hWnd == GetActiveWindow());
3072 WIN_ReleaseWndPtr(wndPtr);
3073 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3074 return wparam;
3079 /*******************************************************************
3080 * GetWindowContextHelpId (USER32.@)
3082 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3084 DWORD retval;
3085 WND *wnd = WIN_FindWndPtr( hwnd );
3086 if (!wnd) return 0;
3087 retval = wnd->helpContext;
3088 WIN_ReleaseWndPtr(wnd);
3089 return retval;
3093 /*******************************************************************
3094 * SetWindowContextHelpId (USER32.@)
3096 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3098 WND *wnd = WIN_FindWndPtr( hwnd );
3099 if (!wnd) return FALSE;
3100 wnd->helpContext = id;
3101 WIN_ReleaseWndPtr(wnd);
3102 return TRUE;
3106 /*******************************************************************
3107 * DRAG_QueryUpdate
3109 * recursively find a child that contains spDragInfo->pt point
3110 * and send WM_QUERYDROPOBJECT
3112 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
3114 BOOL16 wParam, bResult = 0;
3115 POINT pt;
3116 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3117 RECT tempRect;
3119 if (!ptrDragInfo) return FALSE;
3121 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3123 GetWindowRect(hQueryWnd,&tempRect);
3125 if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
3127 if (!IsIconic( hQueryWnd ))
3129 GetClientRect( hQueryWnd, &tempRect );
3130 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
3132 if (PtInRect( &tempRect, pt))
3134 int i;
3135 HWND *list = WIN_ListChildren( hQueryWnd );
3137 wParam = 0;
3139 if (list)
3141 for (i = 0; list[i]; i++)
3143 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
3145 GetWindowRect( list[i], &tempRect );
3146 if (PtInRect( &tempRect, pt )) break;
3149 if (list[i])
3151 if (IsWindowEnabled( list[i] ))
3152 bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
3154 HeapFree( GetProcessHeap(), 0, list );
3156 if(bResult) return bResult;
3158 else wParam = 1;
3160 else wParam = 1;
3162 ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
3164 ptrDragInfo->hScope = hQueryWnd;
3166 if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
3167 else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
3169 if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3171 return bResult;
3175 /*******************************************************************
3176 * DragDetect (USER32.@)
3178 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3180 MSG msg;
3181 RECT rect;
3183 rect.left = pt.x - wDragWidth;
3184 rect.right = pt.x + wDragWidth;
3186 rect.top = pt.y - wDragHeight;
3187 rect.bottom = pt.y + wDragHeight;
3189 SetCapture(hWnd);
3191 while(1)
3193 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3195 if( msg.message == WM_LBUTTONUP )
3197 ReleaseCapture();
3198 return 0;
3200 if( msg.message == WM_MOUSEMOVE )
3202 POINT tmp;
3203 tmp.x = LOWORD(msg.lParam);
3204 tmp.y = HIWORD(msg.lParam);
3205 if( !PtInRect( &rect, tmp ))
3207 ReleaseCapture();
3208 return 1;
3212 WaitMessage();
3214 return 0;
3217 /******************************************************************************
3218 * DragObject (USER.464)
3220 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3221 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3223 MSG msg;
3224 LPDRAGINFO16 lpDragInfo;
3225 SEGPTR spDragInfo;
3226 HCURSOR16 hOldCursor=0, hBummer=0;
3227 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3228 HCURSOR16 hCurrentCursor = 0;
3229 HWND16 hCurrentWnd = 0;
3231 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3232 spDragInfo = K32WOWGlobalLock16(hDragInfo);
3234 if( !lpDragInfo || !spDragInfo ) return 0L;
3236 if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
3238 GlobalFree16(hDragInfo);
3239 return 0L;
3242 if(hCursor) hOldCursor = SetCursor(hCursor);
3244 lpDragInfo->hWnd = hWnd;
3245 lpDragInfo->hScope = 0;
3246 lpDragInfo->wFlags = wObj;
3247 lpDragInfo->hList = szList; /* near pointer! */
3248 lpDragInfo->hOfStruct = hOfStruct;
3249 lpDragInfo->l = 0L;
3251 SetCapture(hWnd);
3252 ShowCursor( TRUE );
3256 GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
3258 *(lpDragInfo+1) = *lpDragInfo;
3260 lpDragInfo->pt.x = msg.pt.x;
3261 lpDragInfo->pt.y = msg.pt.y;
3263 /* update DRAGINFO struct */
3264 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3266 if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
3267 hCurrentCursor = hCursor;
3268 else
3270 hCurrentCursor = hBummer;
3271 lpDragInfo->hScope = 0;
3273 if( hCurrentCursor )
3274 SetCursor(hCurrentCursor);
3276 /* send WM_DRAGLOOP */
3277 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3278 (LPARAM) spDragInfo );
3279 /* send WM_DRAGSELECT or WM_DRAGMOVE */
3280 if( hCurrentWnd != lpDragInfo->hScope )
3282 if( hCurrentWnd )
3283 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3284 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3285 HIWORD(spDragInfo)) );
3286 hCurrentWnd = lpDragInfo->hScope;
3287 if( hCurrentWnd )
3288 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3290 else
3291 if( hCurrentWnd )
3292 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3294 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3296 ReleaseCapture();
3297 ShowCursor( FALSE );
3299 if( hCursor ) SetCursor( hOldCursor );
3301 if( hCurrentCursor != hBummer )
3302 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3303 (WPARAM16)hWnd, (LPARAM)spDragInfo );
3304 else
3305 msg.lParam = 0;
3306 GlobalFree16(hDragInfo);
3308 return (DWORD)(msg.lParam);
3312 /******************************************************************************
3313 * GetWindowModuleFileNameA (USER32.@)
3315 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3317 FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3318 hwnd, lpszFileName, cchFileNameMax);
3319 return 0;
3322 /******************************************************************************
3323 * GetWindowModuleFileNameW (USER32.@)
3325 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3327 FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3328 hwnd, lpszFileName, cchFileNameMax);
3329 return 0;
3332 /******************************************************************************
3333 * GetWindowInfo (USER32.@)
3334 * hwnd: in
3335 * pwi: out.
3336 * MS Documentation mentions that pwi->cbSize must be set to SIZEOF(WINDOWINFO)
3337 * this may be because this structure changed over time. If this is the
3338 * the case, then please: FIXME.
3339 * Using the structure described in MSDN for 98/ME/NT(4.0 SP3)/2000/XP.
3341 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3343 WND *wndInfo = NULL;
3344 if (!pwi) return FALSE;
3345 if (pwi->cbSize != sizeof(WINDOWINFO))
3347 FIXME("windowinfo->cbSize != sizeof(WINDOWINFO). Please report\n");
3348 return FALSE;
3350 wndInfo = WIN_GetPtr(hwnd);
3351 if (!wndInfo) return FALSE;
3352 if (wndInfo == WND_OTHER_PROCESS)
3354 FIXME("window belong to other process\n");
3355 return FALSE;
3358 pwi->rcWindow = wndInfo->rectWindow;
3359 pwi->rcClient = wndInfo->rectClient;
3360 pwi->dwStyle = wndInfo->dwStyle;
3361 pwi->dwExStyle = wndInfo->dwExStyle;
3362 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3363 /* if active WS_ACTIVECAPTION, else 0 */
3365 pwi->cxWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3366 GetSystemMetrics(SM_CXBORDER) : 0);
3367 pwi->cyWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3368 GetSystemMetrics(SM_CYBORDER) : 0);
3369 /* above two: I'm presuming that borders widths are the same
3370 * for each window - so long as its actually using a border.. */
3372 pwi->atomWindowType = GetClassLongA( hwnd, GCW_ATOM );
3373 pwi->wCreatorVersion = GetVersion();
3374 /* Docs say this should be the version that
3375 * CREATED the window. But eh?.. Isn't that just the
3376 * version we are running.. Unless ofcourse its some wacky
3377 * RPC stuff or something */
3379 WIN_ReleasePtr(wndInfo);
3380 return TRUE;