Notification code cleanup, more traces, etc.
[wine/wine-kai.git] / windows / win.c
blobd19cc09f646e7713dcb0691f7ab658ece07c8f42
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 = 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 if 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) wndPtr->parent = reply->full_parent;
429 SERVER_END_REQ;
430 WIN_ReleasePtr( wndPtr );
434 /***********************************************************************
435 * WIN_SetOwner
437 * Change the owner of a window.
439 HWND WIN_SetOwner( HWND hwnd, HWND owner )
441 WND *win = WIN_GetPtr( hwnd );
442 HWND ret = 0;
444 if (!win) return 0;
445 if (win == WND_OTHER_PROCESS)
447 if (IsWindow(hwnd)) ERR( "cannot set owner %x on other process window %x\n", owner, hwnd );
448 return 0;
450 SERVER_START_REQ( set_window_owner )
452 req->handle = hwnd;
453 req->owner = owner;
454 if (!wine_server_call( req ))
456 win->owner = reply->full_owner;
457 ret = reply->prev_owner;
460 SERVER_END_REQ;
461 WIN_ReleasePtr( win );
462 return ret;
466 /***********************************************************************
467 * WIN_SetStyle
469 * Change the style of a window.
471 LONG WIN_SetStyle( HWND hwnd, LONG style )
473 BOOL ok;
474 LONG ret = 0;
475 WND *win = WIN_GetPtr( hwnd );
477 if (!win) return 0;
478 if (win == WND_OTHER_PROCESS)
480 if (IsWindow(hwnd))
481 ERR( "cannot set style %lx on other process window %x\n", style, hwnd );
482 return 0;
484 if (style == win->dwStyle)
486 WIN_ReleasePtr( win );
487 return style;
489 SERVER_START_REQ( set_window_info )
491 req->handle = hwnd;
492 req->flags = SET_WIN_STYLE;
493 req->style = style;
494 if ((ok = !wine_server_call( req )))
496 ret = reply->old_style;
497 win->dwStyle = style;
500 SERVER_END_REQ;
501 WIN_ReleasePtr( win );
502 if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
503 return ret;
507 /***********************************************************************
508 * WIN_SetExStyle
510 * Change the extended style of a window.
512 LONG WIN_SetExStyle( HWND hwnd, LONG style )
514 LONG ret = 0;
515 WND *win = WIN_GetPtr( hwnd );
517 if (!win) return 0;
518 if (win == WND_OTHER_PROCESS)
520 if (IsWindow(hwnd))
521 ERR( "cannot set exstyle %lx on other process window %x\n", style, hwnd );
522 return 0;
524 if (style == win->dwExStyle)
526 WIN_ReleasePtr( win );
527 return style;
529 SERVER_START_REQ( set_window_info )
531 req->handle = hwnd;
532 req->flags = SET_WIN_EXSTYLE;
533 req->ex_style = style;
534 if (!wine_server_call( req ))
536 ret = reply->old_ex_style;
537 win->dwExStyle = style;
540 SERVER_END_REQ;
541 WIN_ReleasePtr( win );
542 return ret;
546 /***********************************************************************
547 * WIN_SetRectangles
549 * Set the window and client rectangles.
551 void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient )
553 WND *win = WIN_GetPtr( hwnd );
554 BOOL ret;
556 if (!win) return;
557 if (win == WND_OTHER_PROCESS)
559 if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %x\n", hwnd );
560 return;
562 SERVER_START_REQ( set_window_rectangles )
564 req->handle = hwnd;
565 req->window.left = rectWindow->left;
566 req->window.top = rectWindow->top;
567 req->window.right = rectWindow->right;
568 req->window.bottom = rectWindow->bottom;
569 req->client.left = rectClient->left;
570 req->client.top = rectClient->top;
571 req->client.right = rectClient->right;
572 req->client.bottom = rectClient->bottom;
573 ret = !wine_server_call( req );
575 SERVER_END_REQ;
576 if (ret)
578 win->rectWindow = *rectWindow;
579 win->rectClient = *rectClient;
581 TRACE( "win %x window (%d,%d)-(%d,%d) client (%d,%d)-(%d,%d)\n", hwnd,
582 rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom,
583 rectClient->left, rectClient->top, rectClient->right, rectClient->bottom );
585 WIN_ReleasePtr( win );
589 /***********************************************************************
590 * WIN_GetRectangles
592 * Get the window and client rectangles.
594 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
596 WND *win = WIN_GetPtr( hwnd );
597 BOOL ret = TRUE;
599 if (!win) return FALSE;
600 if (win == WND_OTHER_PROCESS)
602 SERVER_START_REQ( get_window_rectangles )
604 req->handle = hwnd;
605 if ((ret = !wine_server_call( req )))
607 if (rectWindow)
609 rectWindow->left = reply->window.left;
610 rectWindow->top = reply->window.top;
611 rectWindow->right = reply->window.right;
612 rectWindow->bottom = reply->window.bottom;
614 if (rectClient)
616 rectClient->left = reply->client.left;
617 rectClient->top = reply->client.top;
618 rectClient->right = reply->client.right;
619 rectClient->bottom = reply->client.bottom;
623 SERVER_END_REQ;
625 else
627 if (rectWindow) *rectWindow = win->rectWindow;
628 if (rectClient) *rectClient = win->rectClient;
629 WIN_ReleasePtr( win );
631 return ret;
635 /***********************************************************************
636 * WIN_DestroyWindow
638 * Destroy storage associated to a window. "Internals" p.358
640 LRESULT WIN_DestroyWindow( HWND hwnd )
642 WND *wndPtr;
643 HWND *list;
645 TRACE("%04x\n", hwnd );
647 if (!(hwnd = WIN_IsCurrentThread( hwnd )))
649 ERR( "window doesn't belong to current thread\n" );
650 return 0;
653 /* free child windows */
654 if ((list = WIN_ListChildren( hwnd )))
656 int i;
657 for (i = 0; list[i]; i++)
659 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
660 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
662 HeapFree( GetProcessHeap(), 0, list );
666 * Clear the update region to make sure no WM_PAINT messages will be
667 * generated for this window while processing the WM_NCDESTROY.
669 RedrawWindow( hwnd, NULL, 0,
670 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
673 * Send the WM_NCDESTROY to the window being destroyed.
675 SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
677 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
679 WINPOS_CheckInternalPos( hwnd );
680 if( hwnd == GetCapture()) ReleaseCapture();
682 /* free resources associated with the window */
684 TIMER_RemoveWindowTimers( hwnd );
686 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
687 wndPtr->hmemTaskQ = 0;
689 if (!(wndPtr->dwStyle & WS_CHILD))
691 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
692 if (menu) DestroyMenu( menu );
694 if (wndPtr->hSysMenu)
696 DestroyMenu( wndPtr->hSysMenu );
697 wndPtr->hSysMenu = 0;
699 USER_Driver.pDestroyWindow( hwnd );
700 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
701 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
702 CLASS_RemoveWindow( wndPtr->class );
703 wndPtr->class = NULL;
704 wndPtr->dwMagic = 0; /* Mark it as invalid */
705 WIN_ReleaseWndPtr( wndPtr );
706 return 0;
709 /***********************************************************************
710 * WIN_DestroyThreadWindows
712 * Destroy all children of 'wnd' owned by the current thread.
713 * Return TRUE if something was done.
715 void WIN_DestroyThreadWindows( HWND hwnd )
717 HWND *list;
718 int i;
720 if (!(list = WIN_ListChildren( hwnd ))) return;
721 for (i = 0; list[i]; i++)
723 if (WIN_IsCurrentThread( list[i] ))
724 DestroyWindow( list[i] );
725 else
726 WIN_DestroyThreadWindows( list[i] );
728 HeapFree( GetProcessHeap(), 0, list );
731 /***********************************************************************
732 * WIN_CreateDesktopWindow
734 * Create the desktop window.
736 BOOL WIN_CreateDesktopWindow(void)
738 struct tagCLASS *class;
739 HWND hwndDesktop;
740 INT wndExtra;
741 DWORD clsStyle;
742 WNDPROC winproc;
743 DCE *dce;
744 CREATESTRUCTA cs;
745 RECT rect;
747 TRACE("Creating desktop window\n");
749 if (!WINPOS_CreateInternalPosAtom() ||
750 !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
751 &wndExtra, &winproc, &clsStyle, &dce )))
752 return FALSE;
754 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM),
755 sizeof(WND) + wndExtra - sizeof(pWndDesktop->wExtra) );
756 if (!pWndDesktop) return FALSE;
757 hwndDesktop = pWndDesktop->hwndSelf;
759 pWndDesktop->tid = 0; /* nobody owns the desktop */
760 pWndDesktop->parent = 0;
761 pWndDesktop->owner = 0;
762 pWndDesktop->class = class;
763 pWndDesktop->text = NULL;
764 pWndDesktop->hmemTaskQ = 0;
765 pWndDesktop->hrgnUpdate = 0;
766 pWndDesktop->clsStyle = clsStyle;
767 pWndDesktop->dce = NULL;
768 pWndDesktop->pVScroll = NULL;
769 pWndDesktop->pHScroll = NULL;
770 pWndDesktop->helpContext = 0;
771 pWndDesktop->flags = 0;
772 pWndDesktop->hSysMenu = 0;
773 pWndDesktop->winproc = winproc;
774 pWndDesktop->cbWndExtra = wndExtra;
776 cs.lpCreateParams = NULL;
777 cs.hInstance = 0;
778 cs.hMenu = 0;
779 cs.hwndParent = 0;
780 cs.x = 0;
781 cs.y = 0;
782 cs.cx = GetSystemMetrics( SM_CXSCREEN );
783 cs.cy = GetSystemMetrics( SM_CYSCREEN );
784 cs.style = pWndDesktop->dwStyle;
785 cs.dwExStyle = pWndDesktop->dwExStyle;
786 cs.lpszName = NULL;
787 cs.lpszClass = DESKTOP_CLASS_ATOM;
789 SetRect( &rect, 0, 0, cs.cx, cs.cy );
790 WIN_SetRectangles( hwndDesktop, &rect, &rect );
792 SERVER_START_REQ( set_window_info )
794 req->handle = hwndDesktop;
795 req->flags = 0; /* don't set anything, just retrieve */
796 wine_server_call( req );
797 pWndDesktop->dwStyle = reply->old_style;
798 pWndDesktop->dwExStyle = reply->old_ex_style;
799 pWndDesktop->hInstance = (ULONG_PTR)reply->old_instance;
800 pWndDesktop->userdata = (ULONG_PTR)reply->old_user_data;
801 pWndDesktop->wIDmenu = reply->old_id;
803 SERVER_END_REQ;
805 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE ))
807 WIN_ReleaseWndPtr( pWndDesktop );
808 return FALSE;
811 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
812 WIN_ReleaseWndPtr( pWndDesktop );
813 return TRUE;
817 /***********************************************************************
818 * WIN_FixCoordinates
820 * Fix the coordinates - Helper for WIN_CreateWindowEx.
821 * returns default show mode in sw.
822 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
824 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
826 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
827 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
829 if (cs->style & (WS_CHILD | WS_POPUP))
831 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
832 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) 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) DPRINTF(" WS_POPUP");
902 if(style & WS_CHILD) DPRINTF(" WS_CHILD");
903 if(style & WS_MINIMIZE) DPRINTF(" WS_MINIMIZE");
904 if(style & WS_VISIBLE) DPRINTF(" WS_VISIBLE");
905 if(style & WS_DISABLED) DPRINTF(" WS_DISABLED");
906 if(style & WS_CLIPSIBLINGS) DPRINTF(" WS_CLIPSIBLINGS");
907 if(style & WS_CLIPCHILDREN) DPRINTF(" WS_CLIPCHILDREN");
908 if(style & WS_MAXIMIZE) DPRINTF(" WS_MAXIMIZE");
909 if((style & WS_CAPTION) == WS_CAPTION) DPRINTF(" WS_CAPTION");
910 else
912 if(style & WS_BORDER) DPRINTF(" WS_BORDER");
913 if(style & WS_DLGFRAME) DPRINTF(" WS_DLGFRAME");
915 if(style & WS_VSCROLL) DPRINTF(" WS_VSCROLL");
916 if(style & WS_HSCROLL) DPRINTF(" WS_HSCROLL");
917 if(style & WS_SYSMENU) DPRINTF(" WS_SYSMENU");
918 if(style & WS_THICKFRAME) DPRINTF(" WS_THICKFRAME");
919 if(style & WS_GROUP) DPRINTF(" WS_GROUP");
920 if(style & WS_TABSTOP) DPRINTF(" WS_TABSTOP");
921 if(style & WS_MINIMIZEBOX) DPRINTF(" WS_MINIMIZEBOX");
922 if(style & WS_MAXIMIZEBOX) DPRINTF(" 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) DPRINTF(" %08lx", style & ~DUMPED_STYLES);
946 DPRINTF("\n");
947 #undef DUMPED_STYLES
949 TRACE( "exstyle:" );
950 if(exstyle & WS_EX_DLGMODALFRAME) DPRINTF(" WS_EX_DLGMODALFRAME");
951 if(exstyle & WS_EX_DRAGDETECT) DPRINTF(" WS_EX_DRAGDETECT");
952 if(exstyle & WS_EX_NOPARENTNOTIFY) DPRINTF(" WS_EX_NOPARENTNOTIFY");
953 if(exstyle & WS_EX_TOPMOST) DPRINTF(" WS_EX_TOPMOST");
954 if(exstyle & WS_EX_ACCEPTFILES) DPRINTF(" WS_EX_ACCEPTFILES");
955 if(exstyle & WS_EX_TRANSPARENT) DPRINTF(" WS_EX_TRANSPARENT");
956 if(exstyle & WS_EX_MDICHILD) DPRINTF(" WS_EX_MDICHILD");
957 if(exstyle & WS_EX_TOOLWINDOW) DPRINTF(" WS_EX_TOOLWINDOW");
958 if(exstyle & WS_EX_WINDOWEDGE) DPRINTF(" WS_EX_WINDOWEDGE");
959 if(exstyle & WS_EX_CLIENTEDGE) DPRINTF(" WS_EX_CLIENTEDGE");
960 if(exstyle & WS_EX_CONTEXTHELP) DPRINTF(" WS_EX_CONTEXTHELP");
961 if(exstyle & WS_EX_RIGHT) DPRINTF(" WS_EX_RIGHT");
962 if(exstyle & WS_EX_RTLREADING) DPRINTF(" WS_EX_RTLREADING");
963 if(exstyle & WS_EX_LEFTSCROLLBAR) DPRINTF(" WS_EX_LEFTSCROLLBAR");
964 if(exstyle & WS_EX_CONTROLPARENT) DPRINTF(" WS_EX_CONTROLPARENT");
965 if(exstyle & WS_EX_STATICEDGE) DPRINTF(" WS_EX_STATICEDGE");
966 if(exstyle & WS_EX_APPWINDOW) DPRINTF(" WS_EX_APPWINDOW");
967 if(exstyle & WS_EX_LAYERED) DPRINTF(" 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) DPRINTF(" %08lx", exstyle & ~DUMPED_EX_STYLES);
990 DPRINTF("\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 struct tagCLASS *classPtr;
1005 WND *wndPtr;
1006 HWND hwnd, parent, owner;
1007 INT wndExtra;
1008 DWORD clsStyle;
1009 WNDPROC winproc;
1010 DCE *dce;
1011 BOOL unicode = (type == WIN_PROC_32W);
1013 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%04x menu=%04x inst=%08x params=%p\n",
1014 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszName) : debugstr_a(cs->lpszName),
1015 (type == WIN_PROC_32W) ? debugstr_w((LPWSTR)cs->lpszClass) : debugstr_a(cs->lpszClass),
1016 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1017 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1019 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1021 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1022 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1024 /* Find the parent window */
1026 parent = GetDesktopWindow();
1027 owner = 0;
1029 if (cs->hwndParent == HWND_MESSAGE)
1031 /* native ole32.OleInitialize uses HWND_MESSAGE to create the
1032 * message window (style: WS_POPUP|WS_DISABLED)
1034 FIXME("Parent is HWND_MESSAGE\n");
1036 else if (cs->hwndParent)
1038 /* Make sure parent is valid */
1039 if (!IsWindow( cs->hwndParent ))
1041 WARN("Bad parent %04x\n", cs->hwndParent );
1042 return 0;
1044 if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1045 parent = WIN_GetFullHandle(cs->hwndParent);
1046 else
1047 owner = GetAncestor( cs->hwndParent, GA_ROOT );
1049 else if ((cs->style & (WS_CHILD|WS_POPUP)) == WS_CHILD)
1051 WARN("No parent for child window\n" );
1052 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1055 /* Find the window class */
1056 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
1057 &wndExtra, &winproc, &clsStyle, &dce )))
1059 WARN("Bad class '%s'\n", cs->lpszClass );
1060 return 0;
1063 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1065 /* Correct the window style - stage 1
1067 * These are patches that appear to affect both the style loaded into the
1068 * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
1070 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1071 * why does the user get to set it?
1074 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1075 * tested for WS_POPUP
1077 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1078 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1079 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1080 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1081 else
1082 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1084 /* Create the window structure */
1086 if (!(wndPtr = create_window_handle( parent, owner, classAtom,
1087 sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
1089 TRACE("out of memory\n" );
1090 return 0;
1092 hwnd = wndPtr->hwndSelf;
1094 /* Fill the window structure */
1096 wndPtr->tid = GetCurrentThreadId();
1097 wndPtr->owner = owner;
1098 wndPtr->parent = parent;
1099 wndPtr->class = classPtr;
1100 wndPtr->winproc = winproc;
1101 wndPtr->hInstance = cs->hInstance;
1102 wndPtr->text = NULL;
1103 wndPtr->hmemTaskQ = InitThreadInput16( 0, 0 );
1104 wndPtr->hrgnUpdate = 0;
1105 wndPtr->hrgnWnd = 0;
1106 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1107 wndPtr->dwExStyle = cs->dwExStyle;
1108 wndPtr->clsStyle = clsStyle;
1109 wndPtr->wIDmenu = 0;
1110 wndPtr->helpContext = 0;
1111 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1112 wndPtr->pVScroll = NULL;
1113 wndPtr->pHScroll = NULL;
1114 wndPtr->userdata = 0;
1115 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU)
1116 ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1117 wndPtr->cbWndExtra = wndExtra;
1119 if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
1121 /* Correct the window style - stage 2 */
1123 if (!(cs->style & WS_CHILD))
1125 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1126 if (!(cs->style & WS_POPUP))
1128 wndPtr->dwStyle |= WS_CAPTION;
1129 wndPtr->flags |= WIN_NEED_SIZE;
1132 SERVER_START_REQ( set_window_info )
1134 req->handle = hwnd;
1135 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1136 req->style = wndPtr->dwStyle;
1137 req->ex_style = wndPtr->dwExStyle;
1138 req->instance = (void *)wndPtr->hInstance;
1139 wine_server_call( req );
1141 SERVER_END_REQ;
1143 /* Get class or window DC if needed */
1145 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1146 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
1147 else wndPtr->dce = NULL;
1149 /* Set the window menu */
1151 if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
1153 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1154 else
1156 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1157 if (menuName)
1159 if (HIWORD(cs->hInstance))
1160 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1161 else
1162 cs->hMenu = LoadMenu16(cs->hInstance,menuName);
1164 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1168 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1169 WIN_ReleaseWndPtr( wndPtr );
1171 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1173 WIN_DestroyWindow( hwnd );
1174 return 0;
1177 /* Notify the parent window only */
1179 send_parent_notify( hwnd, WM_CREATE );
1180 if (!IsWindow( hwnd )) return 0;
1182 if (cs->style & WS_VISIBLE)
1184 /* in case WS_VISIBLE got set in the meantime */
1185 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1186 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1187 WIN_ReleasePtr( wndPtr );
1188 ShowWindow( hwnd, sw );
1191 /* Call WH_SHELL hook */
1193 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1194 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
1196 TRACE("created window %04x\n", hwnd);
1197 return hwnd;
1201 /***********************************************************************
1202 * CreateWindow (USER.41)
1204 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1205 DWORD style, INT16 x, INT16 y, INT16 width,
1206 INT16 height, HWND16 parent, HMENU16 menu,
1207 HINSTANCE16 instance, LPVOID data )
1209 return CreateWindowEx16( 0, className, windowName, style,
1210 x, y, width, height, parent, menu, instance, data );
1214 /***********************************************************************
1215 * CreateWindowEx (USER.452)
1217 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1218 LPCSTR windowName, DWORD style, INT16 x,
1219 INT16 y, INT16 width, INT16 height,
1220 HWND16 parent, HMENU16 menu,
1221 HINSTANCE16 instance, LPVOID data )
1223 ATOM classAtom;
1224 CREATESTRUCTA cs;
1225 char buffer[256];
1227 /* Find the class atom */
1229 if (HIWORD(className))
1231 if (!(classAtom = GlobalFindAtomA( className )))
1233 ERR( "bad class name %s\n", debugstr_a(className) );
1234 return 0;
1237 else
1239 classAtom = LOWORD(className);
1240 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1242 ERR( "bad atom %x\n", classAtom);
1243 return 0;
1245 className = buffer;
1248 /* Fix the coordinates */
1250 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1251 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1252 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1253 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1255 /* Create the window */
1257 cs.lpCreateParams = data;
1258 cs.hInstance = (HINSTANCE)instance;
1259 cs.hMenu = (HMENU)menu;
1260 cs.hwndParent = WIN_Handle32( parent );
1261 cs.style = style;
1262 cs.lpszName = windowName;
1263 cs.lpszClass = className;
1264 cs.dwExStyle = exStyle;
1266 return HWND_16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1270 /***********************************************************************
1271 * CreateWindowExA (USER32.@)
1273 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1274 LPCSTR windowName, DWORD style, INT x,
1275 INT y, INT width, INT height,
1276 HWND parent, HMENU menu,
1277 HINSTANCE instance, LPVOID data )
1279 ATOM classAtom;
1280 CREATESTRUCTA cs;
1281 char buffer[256];
1283 if(!instance)
1284 instance=GetModuleHandleA(NULL);
1286 if(exStyle & WS_EX_MDICHILD)
1287 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1289 /* Find the class atom */
1291 if (HIWORD(className))
1293 if (!(classAtom = GlobalFindAtomA( className )))
1295 ERR( "bad class name %s\n", debugstr_a(className) );
1296 return 0;
1299 else
1301 classAtom = LOWORD(className);
1302 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1304 ERR( "bad atom %x\n", classAtom);
1305 return 0;
1307 className = buffer;
1310 /* Create the window */
1312 cs.lpCreateParams = data;
1313 cs.hInstance = instance;
1314 cs.hMenu = menu;
1315 cs.hwndParent = parent;
1316 cs.x = x;
1317 cs.y = y;
1318 cs.cx = width;
1319 cs.cy = height;
1320 cs.style = style;
1321 cs.lpszName = windowName;
1322 cs.lpszClass = className;
1323 cs.dwExStyle = exStyle;
1325 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1329 /***********************************************************************
1330 * CreateWindowExW (USER32.@)
1332 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1333 LPCWSTR windowName, DWORD style, INT x,
1334 INT y, INT width, INT height,
1335 HWND parent, HMENU menu,
1336 HINSTANCE instance, LPVOID data )
1338 ATOM classAtom;
1339 CREATESTRUCTW cs;
1340 WCHAR buffer[256];
1342 if(!instance)
1343 instance=GetModuleHandleA(NULL);
1345 if(exStyle & WS_EX_MDICHILD)
1346 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1348 /* Find the class atom */
1350 if (HIWORD(className))
1352 if (!(classAtom = GlobalFindAtomW( className )))
1354 ERR( "bad class name %s\n", debugstr_w(className) );
1355 return 0;
1358 else
1360 classAtom = LOWORD(className);
1361 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1363 ERR( "bad atom %x\n", classAtom);
1364 return 0;
1366 className = buffer;
1369 /* Create the window */
1371 cs.lpCreateParams = data;
1372 cs.hInstance = instance;
1373 cs.hMenu = menu;
1374 cs.hwndParent = parent;
1375 cs.x = x;
1376 cs.y = y;
1377 cs.cx = width;
1378 cs.cy = height;
1379 cs.style = style;
1380 cs.lpszName = windowName;
1381 cs.lpszClass = className;
1382 cs.dwExStyle = exStyle;
1384 /* Note: we rely on the fact that CREATESTRUCTA and */
1385 /* CREATESTRUCTW have the same layout. */
1386 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1390 /***********************************************************************
1391 * WIN_SendDestroyMsg
1393 static void WIN_SendDestroyMsg( HWND hwnd )
1395 if( CARET_GetHwnd() == hwnd) DestroyCaret();
1396 if (USER_Driver.pResetSelectionOwner)
1397 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1400 * Send the WM_DESTROY to the window.
1402 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1405 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1406 * make sure that the window still exists when we come back.
1408 if (IsWindow(hwnd))
1410 HWND* pWndArray;
1411 int i;
1413 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1415 /* start from the end (FIXME: is this needed?) */
1416 for (i = 0; pWndArray[i]; i++) ;
1418 while (--i >= 0)
1420 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1422 HeapFree( GetProcessHeap(), 0, pWndArray );
1424 else
1425 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1429 /***********************************************************************
1430 * DestroyWindow (USER32.@)
1432 BOOL WINAPI DestroyWindow( HWND hwnd )
1434 BOOL is_child;
1435 HWND h;
1437 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1439 SetLastError( ERROR_ACCESS_DENIED );
1440 return FALSE;
1443 TRACE("(%04x)\n", hwnd);
1445 /* Look whether the focus is within the tree of windows we will
1446 * be destroying.
1448 h = GetFocus();
1449 if (h == hwnd || IsChild( hwnd, h ))
1451 HWND parent = GetAncestor( hwnd, GA_PARENT );
1452 if (parent == GetDesktopWindow()) parent = 0;
1453 SetFocus( parent );
1456 /* Call hooks */
1458 if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
1460 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1462 if (is_child)
1464 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1465 send_parent_notify( hwnd, WM_DESTROY );
1467 else if (!GetWindow( hwnd, GW_OWNER ))
1469 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
1470 /* FIXME: clean up palette - see "Internals" p.352 */
1473 if (!IsWindow(hwnd)) return TRUE;
1475 if (USER_Driver.pResetSelectionOwner)
1476 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1478 /* Hide the window */
1480 if (!ShowWindow( hwnd, SW_HIDE ))
1482 if (hwnd == GetActiveWindow()) WINPOS_ActivateOtherWindow( hwnd );
1484 if (!IsWindow(hwnd)) return TRUE;
1486 /* Recursively destroy owned windows */
1488 if (!is_child)
1490 for (;;)
1492 int i, got_one = 0;
1493 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1494 if (list)
1496 for (i = 0; list[i]; i++)
1498 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1499 if (WIN_IsCurrentThread( list[i] ))
1501 DestroyWindow( list[i] );
1502 got_one = 1;
1503 continue;
1505 WIN_SetOwner( list[i], 0 );
1507 HeapFree( GetProcessHeap(), 0, list );
1509 if (!got_one) break;
1513 /* Send destroy messages */
1515 WIN_SendDestroyMsg( hwnd );
1516 if (!IsWindow( hwnd )) return TRUE;
1518 /* Unlink now so we won't bother with the children later on */
1520 WIN_UnlinkWindow( hwnd );
1522 /* Destroy the window storage */
1524 WIN_DestroyWindow( hwnd );
1525 return TRUE;
1529 /***********************************************************************
1530 * CloseWindow (USER32.@)
1532 BOOL WINAPI CloseWindow( HWND hwnd )
1534 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1535 ShowWindow( hwnd, SW_MINIMIZE );
1536 return TRUE;
1540 /***********************************************************************
1541 * OpenIcon (USER32.@)
1543 BOOL WINAPI OpenIcon( HWND hwnd )
1545 if (!IsIconic( hwnd )) return FALSE;
1546 ShowWindow( hwnd, SW_SHOWNORMAL );
1547 return TRUE;
1551 /***********************************************************************
1552 * WIN_FindWindow
1554 * Implementation of FindWindow() and FindWindowEx().
1556 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1558 HWND *list = NULL;
1559 HWND retvalue = 0;
1560 int i = 0, len = 0;
1561 WCHAR *buffer = NULL;
1563 if (!parent) parent = GetDesktopWindow();
1564 if (title)
1566 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1567 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1570 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1572 if (child)
1574 child = WIN_GetFullHandle( child );
1575 while (list[i] && list[i] != child) i++;
1576 if (!list[i]) goto done;
1577 i++; /* start from next window */
1580 if (title)
1582 while (list[i])
1584 if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1585 i++;
1588 retvalue = list[i];
1590 done:
1591 if (list) HeapFree( GetProcessHeap(), 0, list );
1592 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1593 return retvalue;
1598 /***********************************************************************
1599 * FindWindowA (USER32.@)
1601 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1603 HWND ret = FindWindowExA( 0, 0, className, title );
1604 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1605 return ret;
1609 /***********************************************************************
1610 * FindWindowExA (USER32.@)
1612 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1613 LPCSTR className, LPCSTR title )
1615 ATOM atom = 0;
1616 LPWSTR buffer;
1617 HWND hwnd;
1618 INT len;
1620 if (className)
1622 /* If the atom doesn't exist, then no class */
1623 /* with this name exists either. */
1624 if (!(atom = GlobalFindAtomA( className )))
1626 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1627 return 0;
1630 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1632 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1633 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1634 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1635 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1636 HeapFree( GetProcessHeap(), 0, buffer );
1637 return hwnd;
1641 /***********************************************************************
1642 * FindWindowExW (USER32.@)
1644 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1645 LPCWSTR className, LPCWSTR title )
1647 ATOM atom = 0;
1649 if (className)
1651 /* If the atom doesn't exist, then no class */
1652 /* with this name exists either. */
1653 if (!(atom = GlobalFindAtomW( className )))
1655 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1656 return 0;
1659 return WIN_FindWindow( parent, child, atom, title );
1663 /***********************************************************************
1664 * FindWindowW (USER32.@)
1666 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1668 return FindWindowExW( 0, 0, className, title );
1672 /**********************************************************************
1673 * GetDesktopWindow (USER32.@)
1675 HWND WINAPI GetDesktopWindow(void)
1677 if (pWndDesktop) return pWndDesktop->hwndSelf;
1678 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" );
1679 ExitProcess(1);
1680 return 0;
1684 /*******************************************************************
1685 * EnableWindow (USER32.@)
1687 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1689 WND *wndPtr;
1690 BOOL retvalue;
1691 LONG style;
1692 HWND full_handle;
1694 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1695 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1697 hwnd = full_handle;
1699 TRACE("( %x, %d )\n", hwnd, enable);
1701 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1702 style = wndPtr->dwStyle;
1703 retvalue = ((style & WS_DISABLED) != 0);
1704 WIN_ReleasePtr( wndPtr );
1706 if (enable && retvalue)
1708 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1709 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1711 else if (!enable && !retvalue)
1713 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1715 WIN_SetStyle( hwnd, style | WS_DISABLED );
1717 if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
1718 SetFocus( 0 ); /* A disabled window can't have the focus */
1720 if (hwnd == GetCapture() || IsChild(hwnd, GetCapture()))
1721 ReleaseCapture(); /* A disabled window can't capture the mouse */
1723 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1725 return retvalue;
1729 /***********************************************************************
1730 * IsWindowEnabled (USER32.@)
1732 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1734 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1738 /***********************************************************************
1739 * IsWindowUnicode (USER32.@)
1741 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1743 WND * wndPtr;
1744 BOOL retvalue;
1746 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1747 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1748 WIN_ReleaseWndPtr(wndPtr);
1749 return retvalue;
1753 /**********************************************************************
1754 * GetWindowWord (USER32.@)
1756 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1758 if (offset >= 0)
1760 WORD retvalue = 0;
1761 WND *wndPtr = WIN_GetPtr( hwnd );
1762 if (!wndPtr)
1764 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1765 return 0;
1767 if (wndPtr == WND_OTHER_PROCESS)
1769 if (IsWindow( hwnd ))
1770 FIXME( "(%d) not supported yet on other process window %x\n", offset, hwnd );
1771 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1772 return 0;
1774 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1776 WARN("Invalid offset %d\n", offset );
1777 SetLastError( ERROR_INVALID_INDEX );
1779 else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1780 WIN_ReleasePtr( wndPtr );
1781 return retvalue;
1784 switch(offset)
1786 case GWL_HWNDPARENT:
1787 return GetWindowLongW( hwnd, offset );
1788 case GWL_ID:
1789 case GWL_HINSTANCE:
1791 LONG ret = GetWindowLongW( hwnd, offset );
1792 if (HIWORD(ret))
1793 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1794 return LOWORD(ret);
1796 default:
1797 WARN("Invalid offset %d\n", offset );
1798 return 0;
1803 /**********************************************************************
1804 * SetWindowWord (USER32.@)
1806 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1808 WORD *ptr, retval;
1809 WND * wndPtr;
1811 switch(offset)
1813 case GWL_ID:
1814 case GWL_HINSTANCE:
1815 case GWL_HWNDPARENT:
1816 return SetWindowLongW( hwnd, offset, (UINT)newval );
1817 default:
1818 if (offset < 0)
1820 WARN("Invalid offset %d\n", offset );
1821 SetLastError( ERROR_INVALID_INDEX );
1822 return 0;
1826 wndPtr = WIN_GetPtr( hwnd );
1827 if (wndPtr == WND_OTHER_PROCESS)
1829 if (IsWindow(hwnd))
1830 FIXME( "set %d <- %x not supported yet on other process window %x\n",
1831 offset, newval, hwnd );
1832 wndPtr = NULL;
1834 if (!wndPtr)
1836 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1837 return 0;
1840 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1842 WARN("Invalid offset %d\n", offset );
1843 WIN_ReleasePtr(wndPtr);
1844 SetLastError( ERROR_INVALID_INDEX );
1845 return 0;
1847 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1848 retval = *ptr;
1849 *ptr = newval;
1850 WIN_ReleasePtr(wndPtr);
1851 return retval;
1855 /**********************************************************************
1856 * WIN_GetWindowLong
1858 * Helper function for GetWindowLong().
1860 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1862 LONG retvalue = 0;
1863 WND *wndPtr;
1865 if (offset == GWL_HWNDPARENT)
1867 HWND parent = GetAncestor( hwnd, GA_PARENT );
1868 if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
1869 return (LONG)parent;
1872 if (!(wndPtr = WIN_GetPtr( hwnd )))
1874 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1875 return 0;
1878 if (wndPtr == WND_OTHER_PROCESS)
1880 if (offset >= 0)
1882 if (IsWindow(hwnd))
1883 FIXME( "(%d) not supported on other process window %x\n", offset, hwnd );
1884 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1885 return 0;
1887 if (offset == GWL_WNDPROC)
1889 SetLastError( ERROR_ACCESS_DENIED );
1890 return 0;
1892 SERVER_START_REQ( set_window_info )
1894 req->handle = hwnd;
1895 req->flags = 0; /* don't set anything, just retrieve */
1896 if (!wine_server_call_err( req ))
1898 switch(offset)
1900 case GWL_STYLE: retvalue = reply->old_style; break;
1901 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1902 case GWL_ID: retvalue = reply->old_id; break;
1903 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1904 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1905 default:
1906 SetLastError( ERROR_INVALID_INDEX );
1907 break;
1911 SERVER_END_REQ;
1912 return retvalue;
1915 /* now we have a valid wndPtr */
1917 if (offset >= 0)
1919 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1922 * Some programs try to access last element from 16 bit
1923 * code using illegal offset value. Hopefully this is
1924 * what those programs really expect.
1926 if (type == WIN_PROC_16 &&
1927 wndPtr->cbWndExtra >= 4 &&
1928 offset == wndPtr->cbWndExtra - sizeof(WORD))
1930 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1932 ERR( "- replaced invalid offset %d with %d\n",
1933 offset, offset2 );
1935 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1936 WIN_ReleasePtr( wndPtr );
1937 return retvalue;
1939 WARN("Invalid offset %d\n", offset );
1940 WIN_ReleasePtr( wndPtr );
1941 SetLastError( ERROR_INVALID_INDEX );
1942 return 0;
1944 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1945 /* Special case for dialog window procedure */
1946 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1947 retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1948 WIN_ReleasePtr( wndPtr );
1949 return retvalue;
1952 switch(offset)
1954 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
1955 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1956 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1957 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
1958 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1959 case GWL_HINSTANCE: retvalue = wndPtr->hInstance; break;
1960 default:
1961 WARN("Unknown offset %d\n", offset );
1962 SetLastError( ERROR_INVALID_INDEX );
1963 break;
1965 WIN_ReleasePtr(wndPtr);
1966 return retvalue;
1970 /**********************************************************************
1971 * WIN_SetWindowLong
1973 * Helper function for SetWindowLong().
1975 * 0 is the failure code. However, in the case of failure SetLastError
1976 * must be set to distinguish between a 0 return value and a failure.
1978 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1979 WINDOWPROCTYPE type )
1981 LONG retval = 0;
1982 WND *wndPtr;
1984 TRACE( "%x %d %lx %x\n", hwnd, offset, newval, type );
1986 if (!WIN_IsCurrentProcess( hwnd ))
1988 if (offset == GWL_WNDPROC)
1990 SetLastError( ERROR_ACCESS_DENIED );
1991 return 0;
1993 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1996 wndPtr = WIN_GetPtr( hwnd );
1997 if (wndPtr->hwndSelf == GetDesktopWindow())
1999 /* can't change anything on the desktop window */
2000 WIN_ReleasePtr( wndPtr );
2001 SetLastError( ERROR_ACCESS_DENIED );
2002 return 0;
2005 if (offset >= 0)
2007 LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
2008 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
2010 WARN("Invalid offset %d\n", offset );
2011 WIN_ReleasePtr( wndPtr );
2012 SetLastError( ERROR_INVALID_INDEX );
2013 return 0;
2015 /* Special case for dialog window procedure */
2016 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2018 retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
2019 WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
2020 type, WIN_PROC_WINDOW );
2021 WIN_ReleasePtr( wndPtr );
2022 return retval;
2024 retval = *ptr;
2025 *ptr = newval;
2026 WIN_ReleasePtr( wndPtr );
2028 else
2030 STYLESTRUCT style;
2031 BOOL ok;
2033 /* first some special cases */
2034 switch( offset )
2036 case GWL_STYLE:
2037 case GWL_EXSTYLE:
2038 style.styleOld = wndPtr->dwStyle;
2039 style.styleNew = newval;
2040 WIN_ReleasePtr( wndPtr );
2041 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2042 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2043 newval = style.styleNew;
2044 break;
2045 case GWL_HWNDPARENT:
2046 if (wndPtr->parent == GetDesktopWindow())
2048 WIN_ReleasePtr( wndPtr );
2049 return (LONG)WIN_SetOwner( hwnd, (HWND)newval );
2051 else
2053 WIN_ReleasePtr( wndPtr );
2054 return (LONG)SetParent( hwnd, (HWND)newval );
2056 case GWL_WNDPROC:
2057 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2058 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
2059 type, WIN_PROC_WINDOW );
2060 WIN_ReleasePtr( wndPtr );
2061 return retval;
2062 case GWL_ID:
2063 case GWL_HINSTANCE:
2064 case GWL_USERDATA:
2065 break;
2066 default:
2067 WIN_ReleasePtr( wndPtr );
2068 WARN("Invalid offset %d\n", offset );
2069 SetLastError( ERROR_INVALID_INDEX );
2070 return 0;
2073 SERVER_START_REQ( set_window_info )
2075 req->handle = hwnd;
2076 switch(offset)
2078 case GWL_STYLE:
2079 req->flags = SET_WIN_STYLE;
2080 req->style = newval;
2081 break;
2082 case GWL_EXSTYLE:
2083 req->flags = SET_WIN_EXSTYLE;
2084 req->ex_style = newval;
2085 break;
2086 case GWL_ID:
2087 req->flags = SET_WIN_ID;
2088 req->id = newval;
2089 break;
2090 case GWL_HINSTANCE:
2091 req->flags = SET_WIN_INSTANCE;
2092 req->instance = (void *)newval;
2093 break;
2094 case GWL_USERDATA:
2095 req->flags = SET_WIN_USERDATA;
2096 req->user_data = (void *)newval;
2097 break;
2099 if ((ok = !wine_server_call_err( req )))
2101 switch(offset)
2103 case GWL_STYLE:
2104 wndPtr->dwStyle = newval;
2105 retval = reply->old_style;
2106 break;
2107 case GWL_EXSTYLE:
2108 wndPtr->dwExStyle = newval;
2109 retval = reply->old_ex_style;
2110 break;
2111 case GWL_ID:
2112 wndPtr->wIDmenu = newval;
2113 retval = reply->old_id;
2114 break;
2115 case GWL_HINSTANCE:
2116 wndPtr->hInstance = newval;
2117 retval = (HINSTANCE)reply->old_instance;
2118 break;
2119 case GWL_USERDATA:
2120 wndPtr->userdata = newval;
2121 retval = (ULONG_PTR)reply->old_user_data;
2122 break;
2126 SERVER_END_REQ;
2127 WIN_ReleasePtr( wndPtr );
2129 if (!ok) return 0;
2131 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2132 USER_Driver.pSetWindowStyle( hwnd, retval );
2134 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2135 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2138 return retval;
2142 /**********************************************************************
2143 * GetWindowLong (USER.135)
2145 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2147 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2151 /**********************************************************************
2152 * GetWindowLongA (USER32.@)
2154 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2156 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2160 /**********************************************************************
2161 * GetWindowLongW (USER32.@)
2163 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2165 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2169 /**********************************************************************
2170 * SetWindowLong (USER.136)
2172 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2174 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2178 /**********************************************************************
2179 * SetWindowLongA (USER32.@)
2181 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2183 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2187 /**********************************************************************
2188 * SetWindowLongW (USER32.@) Set window attribute
2190 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2191 * value in a window's extra memory.
2193 * The _hwnd_ parameter specifies the window. is the handle to a
2194 * window that has extra memory. The _newval_ parameter contains the
2195 * new attribute or extra memory value. If positive, the _offset_
2196 * parameter is the byte-addressed location in the window's extra
2197 * memory to set. If negative, _offset_ specifies the window
2198 * attribute to set, and should be one of the following values:
2200 * GWL_EXSTYLE The window's extended window style
2202 * GWL_STYLE The window's window style.
2204 * GWL_WNDPROC Pointer to the window's window procedure.
2206 * GWL_HINSTANCE The window's pplication instance handle.
2208 * GWL_ID The window's identifier.
2210 * GWL_USERDATA The window's user-specified data.
2212 * If the window is a dialog box, the _offset_ parameter can be one of
2213 * the following values:
2215 * DWL_DLGPROC The address of the window's dialog box procedure.
2217 * DWL_MSGRESULT The return value of a message
2218 * that the dialog box procedure processed.
2220 * DWL_USER Application specific information.
2222 * RETURNS
2224 * If successful, returns the previous value located at _offset_. Otherwise,
2225 * returns 0.
2227 * NOTES
2229 * Extra memory for a window class is specified by a nonzero cbWndExtra
2230 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2231 * time of class creation.
2233 * Using GWL_WNDPROC to set a new window procedure effectively creates
2234 * a window subclass. Use CallWindowProc() in the new windows procedure
2235 * to pass messages to the superclass's window procedure.
2237 * The user data is reserved for use by the application which created
2238 * the window.
2240 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2241 * instead, call the EnableWindow() function to change the window's
2242 * disabled state.
2244 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2245 * SetParent() instead.
2247 * Win95:
2248 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2249 * it sends WM_STYLECHANGING before changing the settings
2250 * and WM_STYLECHANGED afterwards.
2251 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2253 LONG WINAPI SetWindowLongW(
2254 HWND hwnd, /* [in] window to alter */
2255 INT offset, /* [in] offset, in bytes, of location to alter */
2256 LONG newval /* [in] new value of location */
2258 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2262 /*******************************************************************
2263 * GetWindowTextA (USER32.@)
2265 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2267 WCHAR *buffer;
2269 if (WIN_IsCurrentProcess( hwnd ))
2270 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2272 /* when window belongs to other process, don't send a message */
2273 if (nMaxCount <= 0) return 0;
2274 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2275 get_server_window_text( hwnd, buffer, nMaxCount );
2276 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2277 lpString[nMaxCount-1] = 0;
2278 HeapFree( GetProcessHeap(), 0, buffer );
2279 return strlen(lpString);
2283 /*******************************************************************
2284 * InternalGetWindowText (USER32.@)
2286 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2288 WND *win;
2290 if (nMaxCount <= 0) return 0;
2291 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2292 if (win != WND_OTHER_PROCESS)
2294 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2295 else lpString[0] = 0;
2296 WIN_ReleasePtr( win );
2298 else
2300 get_server_window_text( hwnd, lpString, nMaxCount );
2302 return strlenW(lpString);
2306 /*******************************************************************
2307 * GetWindowTextW (USER32.@)
2309 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2311 if (WIN_IsCurrentProcess( hwnd ))
2312 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2314 /* when window belongs to other process, don't send a message */
2315 if (nMaxCount <= 0) return 0;
2316 get_server_window_text( hwnd, lpString, nMaxCount );
2317 return strlenW(lpString);
2321 /*******************************************************************
2322 * SetWindowText (USER32.@)
2323 * SetWindowTextA (USER32.@)
2325 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2327 if (!WIN_IsCurrentProcess( hwnd ))
2329 FIXME( "cannot set text %s of other process window %x\n", debugstr_a(lpString), hwnd );
2330 SetLastError( ERROR_ACCESS_DENIED );
2331 return FALSE;
2333 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2337 /*******************************************************************
2338 * SetWindowTextW (USER32.@)
2340 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2342 if (!WIN_IsCurrentProcess( hwnd ))
2344 FIXME( "cannot set text %s of other process window %x\n", debugstr_w(lpString), hwnd );
2345 SetLastError( ERROR_ACCESS_DENIED );
2346 return FALSE;
2348 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2352 /*******************************************************************
2353 * GetWindowTextLengthA (USER32.@)
2355 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2357 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2360 /*******************************************************************
2361 * GetWindowTextLengthW (USER32.@)
2363 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2365 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2369 /*******************************************************************
2370 * IsWindow (USER32.@)
2372 BOOL WINAPI IsWindow( HWND hwnd )
2374 WND *ptr;
2375 BOOL ret;
2377 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2379 if (ptr != WND_OTHER_PROCESS)
2381 WIN_ReleasePtr( ptr );
2382 return TRUE;
2385 /* check other processes */
2386 SERVER_START_REQ( get_window_info )
2388 req->handle = hwnd;
2389 ret = !wine_server_call_err( req );
2391 SERVER_END_REQ;
2392 return ret;
2396 /***********************************************************************
2397 * GetWindowThreadProcessId (USER32.@)
2399 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2401 WND *ptr;
2402 DWORD tid = 0;
2404 if (!(ptr = WIN_GetPtr( hwnd )))
2406 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2407 return 0;
2410 if (ptr != WND_OTHER_PROCESS)
2412 /* got a valid window */
2413 tid = ptr->tid;
2414 if (process) *process = GetCurrentProcessId();
2415 WIN_ReleasePtr( ptr );
2416 return tid;
2419 /* check other processes */
2420 SERVER_START_REQ( get_window_info )
2422 req->handle = hwnd;
2423 if (!wine_server_call_err( req ))
2425 tid = (DWORD)reply->tid;
2426 if (process) *process = (DWORD)reply->pid;
2429 SERVER_END_REQ;
2430 return tid;
2434 /*****************************************************************
2435 * GetParent (USER32.@)
2437 HWND WINAPI GetParent( HWND hwnd )
2439 WND *wndPtr;
2440 HWND retvalue = 0;
2442 if (!(wndPtr = WIN_GetPtr( hwnd )))
2444 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2445 return 0;
2447 if (wndPtr == WND_OTHER_PROCESS)
2449 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2450 if (style & (WS_POPUP | WS_CHILD))
2452 SERVER_START_REQ( get_window_tree )
2454 req->handle = hwnd;
2455 if (!wine_server_call_err( req ))
2457 if (style & WS_POPUP) retvalue = reply->owner;
2458 else if (style & WS_CHILD) retvalue = reply->parent;
2461 SERVER_END_REQ;
2464 else
2466 if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2467 else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2468 WIN_ReleasePtr( wndPtr );
2470 return retvalue;
2474 /*****************************************************************
2475 * GetAncestor (USER32.@)
2477 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2479 WND *win;
2480 HWND *list, ret = 0;
2482 switch(type)
2484 case GA_PARENT:
2485 if (!(win = WIN_GetPtr( hwnd )))
2487 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2488 return 0;
2490 if (win != WND_OTHER_PROCESS)
2492 ret = win->parent;
2493 WIN_ReleasePtr( win );
2495 else /* need to query the server */
2497 SERVER_START_REQ( get_window_tree )
2499 req->handle = hwnd;
2500 if (!wine_server_call_err( req )) ret = reply->parent;
2502 SERVER_END_REQ;
2504 break;
2506 case GA_ROOT:
2507 if (!(list = WIN_ListParents( hwnd ))) return 0;
2509 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2510 else
2512 int count = 2;
2513 while (list[count]) count++;
2514 ret = list[count - 2]; /* get the one before the desktop */
2516 HeapFree( GetProcessHeap(), 0, list );
2517 break;
2519 case GA_ROOTOWNER:
2520 if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2521 for (;;)
2523 HWND parent = GetParent( ret );
2524 if (!parent) break;
2525 ret = parent;
2527 break;
2529 return ret;
2533 /*****************************************************************
2534 * SetParent (USER32.@)
2536 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2538 WND *wndPtr;
2539 HWND retvalue, full_handle;
2540 BOOL was_visible;
2542 if (!parent) parent = GetDesktopWindow();
2543 else parent = WIN_GetFullHandle( parent );
2545 if (!IsWindow( parent ))
2547 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2548 return 0;
2551 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2552 return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2554 hwnd = full_handle;
2556 if (USER_Driver.pSetParent)
2557 return USER_Driver.pSetParent( hwnd, parent );
2559 /* Windows hides the window first, then shows it again
2560 * including the WM_SHOWWINDOW messages and all */
2561 was_visible = ShowWindow( hwnd, SW_HIDE );
2563 if (!IsWindow( parent )) return 0;
2564 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2566 retvalue = wndPtr->parent; /* old parent */
2567 if (parent != retvalue)
2569 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2571 if (parent != GetDesktopWindow()) /* a child window */
2573 if (!(wndPtr->dwStyle & WS_CHILD))
2575 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2576 if (menu) DestroyMenu( menu );
2580 WIN_ReleasePtr( wndPtr );
2582 /* SetParent additionally needs to make hwnd the topmost window
2583 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2584 WM_WINDOWPOSCHANGED notification messages.
2586 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2587 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2588 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2589 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2590 return retvalue;
2594 /*******************************************************************
2595 * IsChild (USER32.@)
2597 BOOL WINAPI IsChild( HWND parent, HWND child )
2599 HWND *list = WIN_ListParents( child );
2600 int i;
2601 BOOL ret;
2603 if (!list) return FALSE;
2604 parent = WIN_GetFullHandle( parent );
2605 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2606 ret = (list[i] != 0);
2607 HeapFree( GetProcessHeap(), 0, list );
2608 return ret;
2612 /***********************************************************************
2613 * IsWindowVisible (USER32.@)
2615 BOOL WINAPI IsWindowVisible( HWND hwnd )
2617 HWND *list;
2618 BOOL retval;
2619 int i;
2621 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2622 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2623 for (i = 0; list[i]; i++)
2624 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2625 retval = !list[i];
2626 HeapFree( GetProcessHeap(), 0, list );
2627 return retval;
2631 /***********************************************************************
2632 * WIN_IsWindowDrawable
2634 * hwnd is drawable when it is visible, all parents are not
2635 * minimized, and it is itself not minimized unless we are
2636 * trying to draw its default class icon.
2638 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2640 HWND *list;
2641 BOOL retval;
2642 int i;
2643 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2645 if (!(style & WS_VISIBLE)) return FALSE;
2646 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2648 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2649 for (i = 0; list[i]; i++)
2650 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2651 break;
2652 retval = !list[i];
2653 HeapFree( GetProcessHeap(), 0, list );
2654 return retval;
2658 /*******************************************************************
2659 * GetTopWindow (USER32.@)
2661 HWND WINAPI GetTopWindow( HWND hwnd )
2663 if (!hwnd) hwnd = GetDesktopWindow();
2664 return GetWindow( hwnd, GW_CHILD );
2668 /*******************************************************************
2669 * GetWindow (USER32.@)
2671 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2673 HWND retval = 0;
2675 if (rel == GW_OWNER) /* this one may be available locally */
2677 WND *wndPtr = WIN_GetPtr( hwnd );
2678 if (!wndPtr)
2680 SetLastError( ERROR_INVALID_HANDLE );
2681 return 0;
2683 if (wndPtr != WND_OTHER_PROCESS)
2685 retval = wndPtr->owner;
2686 WIN_ReleasePtr( wndPtr );
2687 return retval;
2689 /* else fall through to server call */
2692 SERVER_START_REQ( get_window_tree )
2694 req->handle = hwnd;
2695 if (!wine_server_call_err( req ))
2697 switch(rel)
2699 case GW_HWNDFIRST:
2700 retval = reply->first_sibling;
2701 break;
2702 case GW_HWNDLAST:
2703 retval = reply->last_sibling;
2704 break;
2705 case GW_HWNDNEXT:
2706 retval = reply->next_sibling;
2707 break;
2708 case GW_HWNDPREV:
2709 retval = reply->prev_sibling;
2710 break;
2711 case GW_OWNER:
2712 retval = reply->owner;
2713 break;
2714 case GW_CHILD:
2715 retval = reply->first_child;
2716 break;
2720 SERVER_END_REQ;
2721 return retval;
2725 /***********************************************************************
2726 * WIN_InternalShowOwnedPopups
2728 * Internal version of ShowOwnedPopups; Wine functions should use this
2729 * to avoid interfering with application calls to ShowOwnedPopups
2730 * and to make sure the application can't prevent showing/hiding.
2732 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2736 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2738 int count = 0;
2739 WND *pWnd;
2740 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2742 if (!win_array) return TRUE;
2745 * Show windows Lowest first, Highest last to preserve Z-Order
2747 while (win_array[count]) count++;
2748 while (--count >= 0)
2750 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2751 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2753 if (pWnd->dwStyle & WS_POPUP)
2755 if (fShow)
2757 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2758 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2761 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2763 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2764 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2767 else
2769 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2770 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2771 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2774 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2776 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2777 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2778 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2782 WIN_ReleaseWndPtr( pWnd );
2784 HeapFree( GetProcessHeap(), 0, win_array );
2786 return TRUE;
2789 /*******************************************************************
2790 * ShowOwnedPopups (USER32.@)
2792 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2794 int count = 0;
2795 WND *pWnd;
2796 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2798 if (!win_array) return TRUE;
2800 while (win_array[count]) count++;
2801 while (--count >= 0)
2803 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2804 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2806 if (pWnd->dwStyle & WS_POPUP)
2808 if (fShow)
2810 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2812 /* In Windows, ShowOwnedPopups(TRUE) generates
2813 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2814 * regardless of the state of the owner
2816 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2817 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2820 else
2822 if (IsWindowVisible(pWnd->hwndSelf))
2824 /* In Windows, ShowOwnedPopups(FALSE) generates
2825 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2826 * regardless of the state of the owner
2828 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2829 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2833 WIN_ReleaseWndPtr( pWnd );
2835 HeapFree( GetProcessHeap(), 0, win_array );
2836 return TRUE;
2840 /*******************************************************************
2841 * GetLastActivePopup (USER32.@)
2843 HWND WINAPI GetLastActivePopup( HWND hwnd )
2845 HWND retval = hwnd;
2847 SERVER_START_REQ( get_window_info )
2849 req->handle = hwnd;
2850 if (!wine_server_call_err( req )) retval = reply->last_active;
2852 SERVER_END_REQ;
2853 return retval;
2857 /*******************************************************************
2858 * WIN_ListParents
2860 * Build an array of all parents of a given window, starting with
2861 * the immediate parent. The array must be freed with HeapFree.
2862 * Returns NULL if window is a top-level window.
2864 HWND *WIN_ListParents( HWND hwnd )
2866 WND *win;
2867 HWND current, *list;
2868 int pos = 0, size = 16, count = 0;
2870 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2872 current = hwnd;
2873 for (;;)
2875 if (!(win = WIN_GetPtr( current ))) goto empty;
2876 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2877 list[pos] = win->parent;
2878 WIN_ReleasePtr( win );
2879 if (!(current = list[pos]))
2881 if (!pos) goto empty;
2882 return list;
2884 if (++pos == size - 1)
2886 /* need to grow the list */
2887 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2888 if (!new_list) goto empty;
2889 list = new_list;
2890 size += 16;
2894 /* at least one parent belongs to another process, have to query the server */
2896 for (;;)
2898 count = 0;
2899 SERVER_START_REQ( get_window_parents )
2901 req->handle = hwnd;
2902 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2903 if (!wine_server_call( req )) count = reply->count;
2905 SERVER_END_REQ;
2906 if (!count) goto empty;
2907 if (size > count)
2909 list[count] = 0;
2910 return list;
2912 HeapFree( GetProcessHeap(), 0, list );
2913 size = count + 1;
2914 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2917 empty:
2918 HeapFree( GetProcessHeap(), 0, list );
2919 return NULL;
2923 /*******************************************************************
2924 * WIN_ListChildren
2926 * Build an array of the children of a given window. The array must be
2927 * freed with HeapFree. Returns NULL when no windows are found.
2929 HWND *WIN_ListChildren( HWND hwnd )
2931 return list_window_children( hwnd, 0, 0 );
2935 /*******************************************************************
2936 * EnumWindows (USER32.@)
2938 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2940 HWND *list;
2941 BOOL ret = TRUE;
2942 int i, iWndsLocks;
2944 /* We have to build a list of all windows first, to avoid */
2945 /* unpleasant side-effects, for instance if the callback */
2946 /* function changes the Z-order of the windows. */
2948 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2950 /* Now call the callback function for every window */
2952 iWndsLocks = WIN_SuspendWndsLock();
2953 for (i = 0; list[i]; i++)
2955 /* Make sure that the window still exists */
2956 if (!IsWindow( list[i] )) continue;
2957 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2959 WIN_RestoreWndsLock(iWndsLocks);
2960 HeapFree( GetProcessHeap(), 0, list );
2961 return ret;
2965 /**********************************************************************
2966 * EnumThreadWindows (USER32.@)
2968 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2970 HWND *list;
2971 int i, iWndsLocks;
2973 if (!(list = list_window_children( GetDesktopWindow(), 0, GetCurrentThreadId() )))
2974 return TRUE ;
2976 /* Now call the callback function for every window */
2978 iWndsLocks = WIN_SuspendWndsLock();
2979 for (i = 0; list[i]; i++)
2980 if (!func( list[i], lParam )) break;
2981 WIN_RestoreWndsLock(iWndsLocks);
2982 HeapFree( GetProcessHeap(), 0, list );
2983 return TRUE;
2987 /**********************************************************************
2988 * WIN_EnumChildWindows
2990 * Helper function for EnumChildWindows().
2992 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2994 HWND *childList;
2995 BOOL ret = FALSE;
2997 for ( ; *list; list++)
2999 /* Make sure that the window still exists */
3000 if (!IsWindow( *list )) continue;
3001 /* skip owned windows */
3002 if (GetWindow( *list, GW_OWNER )) continue;
3003 /* Build children list first */
3004 childList = WIN_ListChildren( *list );
3006 ret = func( *list, lParam );
3008 if (childList)
3010 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3011 HeapFree( GetProcessHeap(), 0, childList );
3013 if (!ret) return FALSE;
3015 return TRUE;
3019 /**********************************************************************
3020 * EnumChildWindows (USER32.@)
3022 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3024 HWND *list;
3025 int iWndsLocks;
3027 if (!(list = WIN_ListChildren( parent ))) return FALSE;
3028 iWndsLocks = WIN_SuspendWndsLock();
3029 WIN_EnumChildWindows( list, func, lParam );
3030 WIN_RestoreWndsLock(iWndsLocks);
3031 HeapFree( GetProcessHeap(), 0, list );
3032 return TRUE;
3036 /*******************************************************************
3037 * AnyPopup (USER.52)
3039 BOOL16 WINAPI AnyPopup16(void)
3041 return AnyPopup();
3045 /*******************************************************************
3046 * AnyPopup (USER32.@)
3048 BOOL WINAPI AnyPopup(void)
3050 int i;
3051 BOOL retvalue;
3052 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3054 if (!list) return FALSE;
3055 for (i = 0; list[i]; i++)
3057 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3059 retvalue = (list[i] != 0);
3060 HeapFree( GetProcessHeap(), 0, list );
3061 return retvalue;
3065 /*******************************************************************
3066 * FlashWindow (USER32.@)
3068 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3070 WND *wndPtr = WIN_FindWndPtr(hWnd);
3072 TRACE("%04x\n", hWnd);
3074 if (!wndPtr) return FALSE;
3075 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3077 if (wndPtr->dwStyle & WS_MINIMIZE)
3079 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3081 HDC hDC = GetDC(hWnd);
3083 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
3084 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3086 ReleaseDC( hWnd, hDC );
3087 wndPtr->flags |= WIN_NCACTIVATED;
3089 else
3091 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3092 wndPtr->flags &= ~WIN_NCACTIVATED;
3094 WIN_ReleaseWndPtr(wndPtr);
3095 return TRUE;
3097 else
3099 WPARAM16 wparam;
3100 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3101 else wparam = (hWnd == GetForegroundWindow());
3103 WIN_ReleaseWndPtr(wndPtr);
3104 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3105 return wparam;
3110 /*******************************************************************
3111 * GetWindowContextHelpId (USER32.@)
3113 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3115 DWORD retval;
3116 WND *wnd = WIN_FindWndPtr( hwnd );
3117 if (!wnd) return 0;
3118 retval = wnd->helpContext;
3119 WIN_ReleaseWndPtr(wnd);
3120 return retval;
3124 /*******************************************************************
3125 * SetWindowContextHelpId (USER32.@)
3127 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3129 WND *wnd = WIN_FindWndPtr( hwnd );
3130 if (!wnd) return FALSE;
3131 wnd->helpContext = id;
3132 WIN_ReleaseWndPtr(wnd);
3133 return TRUE;
3137 /*******************************************************************
3138 * DRAG_QueryUpdate16
3140 * recursively find a child that contains spDragInfo->pt point
3141 * and send WM_QUERYDROPOBJECT
3143 static BOOL16 DRAG_QueryUpdate16( HWND hQueryWnd, SEGPTR spDragInfo )
3145 BOOL16 wParam, bResult = 0;
3146 POINT pt;
3147 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3148 RECT tempRect;
3150 if (!ptrDragInfo) return FALSE;
3152 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3154 GetWindowRect(hQueryWnd,&tempRect);
3156 if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
3158 if (!IsIconic( hQueryWnd ))
3160 GetClientRect( hQueryWnd, &tempRect );
3161 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
3163 if (PtInRect( &tempRect, pt))
3165 int i;
3166 HWND *list = WIN_ListChildren( hQueryWnd );
3168 wParam = 0;
3170 if (list)
3172 for (i = 0; list[i]; i++)
3174 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
3176 GetWindowRect( list[i], &tempRect );
3177 if (PtInRect( &tempRect, pt )) break;
3180 if (list[i])
3182 if (IsWindowEnabled( list[i] ))
3183 bResult = DRAG_QueryUpdate16( list[i], spDragInfo );
3185 HeapFree( GetProcessHeap(), 0, list );
3187 if(bResult) return bResult;
3189 else wParam = 1;
3191 else wParam = 1;
3193 ScreenToClient16(HWND_16(hQueryWnd),&ptrDragInfo->pt);
3195 ptrDragInfo->hScope = HWND_16(hQueryWnd);
3197 bResult = SendMessage16( HWND_16(hQueryWnd), WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
3199 if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3201 return bResult;
3205 /*******************************************************************
3206 * DragDetect (USER32.@)
3208 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3210 MSG msg;
3211 RECT rect;
3213 rect.left = pt.x - wDragWidth;
3214 rect.right = pt.x + wDragWidth;
3216 rect.top = pt.y - wDragHeight;
3217 rect.bottom = pt.y + wDragHeight;
3219 SetCapture(hWnd);
3221 while(1)
3223 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3225 if( msg.message == WM_LBUTTONUP )
3227 ReleaseCapture();
3228 return 0;
3230 if( msg.message == WM_MOUSEMOVE )
3232 POINT tmp;
3233 tmp.x = LOWORD(msg.lParam);
3234 tmp.y = HIWORD(msg.lParam);
3235 if( !PtInRect( &rect, tmp ))
3237 ReleaseCapture();
3238 return 1;
3242 WaitMessage();
3244 return 0;
3247 /******************************************************************************
3248 * DragObject (USER.464)
3250 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3251 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3253 MSG msg;
3254 LPDRAGINFO16 lpDragInfo;
3255 SEGPTR spDragInfo;
3256 HCURSOR hOldCursor=0, hBummer=0;
3257 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3258 HCURSOR hCurrentCursor = 0;
3259 HWND16 hCurrentWnd = 0;
3261 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3262 spDragInfo = K32WOWGlobalLock16(hDragInfo);
3264 if( !lpDragInfo || !spDragInfo ) return 0L;
3266 if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
3268 GlobalFree16(hDragInfo);
3269 return 0L;
3272 if(hCursor) hOldCursor = SetCursor(HCURSOR_32(hCursor));
3274 lpDragInfo->hWnd = hWnd;
3275 lpDragInfo->hScope = 0;
3276 lpDragInfo->wFlags = wObj;
3277 lpDragInfo->hList = szList; /* near pointer! */
3278 lpDragInfo->hOfStruct = hOfStruct;
3279 lpDragInfo->l = 0L;
3281 SetCapture(WIN_Handle32(hWnd));
3282 ShowCursor( TRUE );
3286 GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
3288 *(lpDragInfo+1) = *lpDragInfo;
3290 lpDragInfo->pt.x = msg.pt.x;
3291 lpDragInfo->pt.y = msg.pt.y;
3293 /* update DRAGINFO struct */
3294 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3296 if( DRAG_QueryUpdate16(WIN_Handle32(hwndScope), spDragInfo) > 0 )
3297 hCurrentCursor = HCURSOR_32(hCursor);
3298 else
3300 hCurrentCursor = hBummer;
3301 lpDragInfo->hScope = 0;
3303 if( hCurrentCursor )
3304 SetCursor(hCurrentCursor);
3306 /* send WM_DRAGLOOP */
3307 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3308 (LPARAM) spDragInfo );
3309 /* send WM_DRAGSELECT or WM_DRAGMOVE */
3310 if( hCurrentWnd != lpDragInfo->hScope )
3312 if( hCurrentWnd )
3313 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3314 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3315 HIWORD(spDragInfo)) );
3316 hCurrentWnd = lpDragInfo->hScope;
3317 if( hCurrentWnd )
3318 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3320 else
3321 if( hCurrentWnd )
3322 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3324 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3326 ReleaseCapture();
3327 ShowCursor( FALSE );
3329 if( hCursor ) SetCursor(hOldCursor);
3331 if( hCurrentCursor != hBummer )
3332 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3333 (WPARAM16)hWnd, (LPARAM)spDragInfo );
3334 else
3335 msg.lParam = 0;
3336 GlobalFree16(hDragInfo);
3338 return (DWORD)(msg.lParam);
3342 /******************************************************************************
3343 * GetWindowModuleFileNameA (USER32.@)
3345 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3347 FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3348 hwnd, lpszFileName, cchFileNameMax);
3349 return 0;
3352 /******************************************************************************
3353 * GetWindowModuleFileNameW (USER32.@)
3355 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3357 FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3358 hwnd, lpszFileName, cchFileNameMax);
3359 return 0;
3362 /******************************************************************************
3363 * GetWindowInfo (USER32.@)
3364 * hwnd: in
3365 * pwi: out.
3366 * MS Documentation mentions that pwi->cbSize must be set to SIZEOF(WINDOWINFO)
3367 * this may be because this structure changed over time. If this is the
3368 * the case, then please: FIXME.
3369 * Using the structure described in MSDN for 98/ME/NT(4.0 SP3)/2000/XP.
3371 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3373 WND *wndInfo = NULL;
3374 if (!pwi) return FALSE;
3375 if (pwi->cbSize != sizeof(WINDOWINFO))
3377 FIXME("windowinfo->cbSize != sizeof(WINDOWINFO). Please report\n");
3378 return FALSE;
3380 wndInfo = WIN_GetPtr(hwnd);
3381 if (!wndInfo) return FALSE;
3382 if (wndInfo == WND_OTHER_PROCESS)
3384 FIXME("window belong to other process\n");
3385 return FALSE;
3388 pwi->rcWindow = wndInfo->rectWindow;
3389 pwi->rcClient = wndInfo->rectClient;
3390 pwi->dwStyle = wndInfo->dwStyle;
3391 pwi->dwExStyle = wndInfo->dwExStyle;
3392 pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3393 /* if active WS_ACTIVECAPTION, else 0 */
3395 pwi->cxWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3396 GetSystemMetrics(SM_CXBORDER) : 0);
3397 pwi->cyWindowBorders = ((wndInfo->dwStyle & WS_BORDER) ?
3398 GetSystemMetrics(SM_CYBORDER) : 0);
3399 /* above two: I'm presuming that borders widths are the same
3400 * for each window - so long as its actually using a border.. */
3402 pwi->atomWindowType = GetClassLongA( hwnd, GCW_ATOM );
3403 pwi->wCreatorVersion = GetVersion();
3404 /* Docs say this should be the version that
3405 * CREATED the window. But eh?.. Isn't that just the
3406 * version we are running.. Unless ofcourse its some wacky
3407 * RPC stuff or something */
3409 WIN_ReleasePtr(wndInfo);
3410 return TRUE;