Added LGPL standard comment, and copyright notices where necessary.
[wine/multimedia.git] / windows / win.c
bloba8c715b1feef1d25f17074c02512d4df7f81f198
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 <assert.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include "windef.h"
25 #include "wine/winbase16.h"
26 #include "wine/winuser16.h"
27 #include "wine/server.h"
28 #include "wine/unicode.h"
29 #include "win.h"
30 #include "user.h"
31 #include "dce.h"
32 #include "controls.h"
33 #include "cursoricon.h"
34 #include "hook.h"
35 #include "message.h"
36 #include "queue.h"
37 #include "task.h"
38 #include "winpos.h"
39 #include "winerror.h"
40 #include "stackframe.h"
41 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(win);
44 WINE_DECLARE_DEBUG_CHANNEL(msg);
46 #define NB_USER_HANDLES (LAST_USER_HANDLE - FIRST_USER_HANDLE + 1)
48 /**********************************************************************/
50 /* Desktop window */
51 static WND *pWndDesktop = NULL;
53 static WORD wDragWidth = 4;
54 static WORD wDragHeight= 3;
56 static void *user_handles[NB_USER_HANDLES];
58 /* thread safeness */
59 extern SYSLEVEL USER_SysLevel; /* FIXME */
61 /***********************************************************************
62 * WIN_SuspendWndsLock
64 * Suspend the lock on WND structures.
65 * Returns the number of locks suspended
67 int WIN_SuspendWndsLock( void )
69 int isuspendedLocks = _ConfirmSysLevel( &USER_SysLevel );
70 int count = isuspendedLocks;
72 while ( count-- > 0 )
73 _LeaveSysLevel( &USER_SysLevel );
75 return isuspendedLocks;
78 /***********************************************************************
79 * WIN_RestoreWndsLock
81 * Restore the suspended locks on WND structures
83 void WIN_RestoreWndsLock( int ipreviousLocks )
85 while ( ipreviousLocks-- > 0 )
86 _EnterSysLevel( &USER_SysLevel );
89 /***********************************************************************
90 * create_window_handle
92 * Create a window handle with the server.
94 static WND *create_window_handle( HWND parent, HWND owner, ATOM atom, INT size )
96 BOOL res;
97 user_handle_t handle = 0;
98 WORD index;
99 WND *win = HeapAlloc( GetProcessHeap(), 0, size );
101 if (!win) return NULL;
103 USER_Lock();
105 SERVER_START_REQ( create_window )
107 req->parent = parent;
108 req->owner = owner;
109 req->atom = atom;
110 if ((res = !wine_server_call_err( req ))) handle = reply->handle;
112 SERVER_END_REQ;
114 if (!res)
116 USER_Unlock();
117 HeapFree( GetProcessHeap(), 0, win );
118 return NULL;
120 index = LOWORD(handle) - FIRST_USER_HANDLE;
121 assert( index < NB_USER_HANDLES );
122 user_handles[index] = win;
123 win->hwndSelf = handle;
124 win->dwMagic = WND_MAGIC;
125 win->irefCount = 1;
126 return win;
130 /***********************************************************************
131 * free_window_handle
133 * Free a window handle.
135 static WND *free_window_handle( HWND hwnd )
137 WND *ptr;
138 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
140 if (index >= NB_USER_HANDLES) return NULL;
141 USER_Lock();
142 if ((ptr = user_handles[index]))
144 SERVER_START_REQ( destroy_window )
146 req->handle = hwnd;
147 if (!wine_server_call_err( req ))
148 user_handles[index] = NULL;
149 else
150 ptr = NULL;
152 SERVER_END_REQ;
154 USER_Unlock();
155 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
156 return ptr;
160 /*******************************************************************
161 * list_window_children
163 * Build an array of the children of a given window. The array must be
164 * freed with HeapFree. Returns NULL when no windows are found.
166 static HWND *list_window_children( HWND hwnd, ATOM atom, DWORD tid )
168 HWND *list;
169 int size = 32;
171 for (;;)
173 int count = 0;
175 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) break;
177 SERVER_START_REQ( get_window_children )
179 req->parent = hwnd;
180 req->atom = atom;
181 req->tid = (void *)tid;
182 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
183 if (!wine_server_call( req )) count = reply->count;
185 SERVER_END_REQ;
186 if (count && count < size)
188 list[count] = 0;
189 return list;
191 HeapFree( GetProcessHeap(), 0, list );
192 if (!count) break;
193 size = count + 1; /* restart with a large enough buffer */
195 return NULL;
199 /*******************************************************************
200 * send_parent_notify
202 static void send_parent_notify( HWND hwnd, UINT msg )
204 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD)) return;
205 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_NOPARENTNOTIFY) return;
206 SendMessageW( GetParent(hwnd), WM_PARENTNOTIFY,
207 MAKEWPARAM( msg, GetWindowLongW( hwnd, GWL_ID )), (LPARAM)hwnd );
211 /*******************************************************************
212 * get_server_window_text
214 * Retrieve the window text from the server.
216 static void get_server_window_text( HWND hwnd, LPWSTR text, INT count )
218 size_t len = 0;
220 SERVER_START_REQ( get_window_text )
222 req->handle = hwnd;
223 wine_server_set_reply( req, text, (count - 1) * sizeof(WCHAR) );
224 if (!wine_server_call_err( req )) len = wine_server_reply_size(reply);
226 SERVER_END_REQ;
227 text[len / sizeof(WCHAR)] = 0;
231 /***********************************************************************
232 * WIN_GetPtr
234 * Return a pointer to the WND structure if local to the process,
235 * or WND_OTHER_PROCESS is handle may be valid in other process.
236 * If ret value is a valid pointer, it must be released with WIN_ReleasePtr.
238 WND *WIN_GetPtr( HWND hwnd )
240 WND * ptr;
241 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
243 if (index >= NB_USER_HANDLES) return NULL;
245 USER_Lock();
246 if ((ptr = user_handles[index]))
248 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
249 return ptr;
250 ptr = NULL;
252 else ptr = WND_OTHER_PROCESS;
253 USER_Unlock();
254 return ptr;
258 /***********************************************************************
259 * WIN_IsCurrentProcess
261 * Check whether a given window belongs to the current process (and return the full handle).
263 HWND WIN_IsCurrentProcess( HWND hwnd )
265 WND *ptr;
266 HWND ret;
268 if (!(ptr = WIN_GetPtr( hwnd )) || ptr == WND_OTHER_PROCESS) return 0;
269 ret = ptr->hwndSelf;
270 WIN_ReleasePtr( ptr );
271 return ret;
275 /***********************************************************************
276 * WIN_IsCurrentThread
278 * Check whether a given window belongs to the current thread (and return the full handle).
280 HWND WIN_IsCurrentThread( HWND hwnd )
282 WND *ptr;
283 HWND ret = 0;
285 if ((ptr = WIN_GetPtr( hwnd )) && ptr != WND_OTHER_PROCESS)
287 if (ptr->tid == GetCurrentThreadId()) ret = ptr->hwndSelf;
288 WIN_ReleasePtr( ptr );
290 return ret;
294 /***********************************************************************
295 * WIN_Handle32
297 * Convert a 16-bit window handle to a full 32-bit handle.
299 HWND WIN_Handle32( HWND16 hwnd16 )
301 WND *ptr;
302 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
304 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
305 /* do sign extension for -2 and -3 */
306 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
308 if (!(ptr = WIN_GetPtr( hwnd ))) return hwnd;
310 if (ptr != WND_OTHER_PROCESS)
312 hwnd = ptr->hwndSelf;
313 WIN_ReleasePtr( ptr );
315 else /* may belong to another process */
317 SERVER_START_REQ( get_window_info )
319 req->handle = hwnd;
320 if (!wine_server_call_err( req )) hwnd = reply->full_handle;
322 SERVER_END_REQ;
324 return hwnd;
328 /***********************************************************************
329 * WIN_FindWndPtr
331 * Return a pointer to the WND structure corresponding to a HWND.
333 WND * WIN_FindWndPtr( HWND hwnd )
335 WND * ptr;
337 if (!hwnd) return NULL;
339 if ((ptr = WIN_GetPtr( hwnd )))
341 if (ptr != WND_OTHER_PROCESS)
343 /* increment destruction monitoring */
344 ptr->irefCount++;
345 return ptr;
347 if (IsWindow( hwnd )) /* check other processes */
349 ERR( "window %04x belongs to other process\n", hwnd );
350 /* DbgBreakPoint(); */
353 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
354 return NULL;
358 /***********************************************************************
359 * WIN_ReleaseWndPtr
361 * Release the pointer to the WND structure.
363 void WIN_ReleaseWndPtr(WND *wndPtr)
365 if(!wndPtr) return;
367 /* Decrement destruction monitoring value */
368 wndPtr->irefCount--;
369 /* Check if it's time to release the memory */
370 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
372 /* Release memory */
373 free_window_handle( wndPtr->hwndSelf );
375 else if(wndPtr->irefCount < 0)
377 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
378 ERR("forgot a Lock on %p somewhere\n",wndPtr);
380 /* unlock all WND structures for thread safeness */
381 USER_Unlock();
385 /***********************************************************************
386 * WIN_UnlinkWindow
388 * Remove a window from the siblings linked list.
390 void WIN_UnlinkWindow( HWND hwnd )
392 WIN_LinkWindow( hwnd, 0, 0 );
396 /***********************************************************************
397 * WIN_LinkWindow
399 * Insert a window into the siblings linked list.
400 * The window is inserted after the specified window, which can also
401 * be specified as HWND_TOP or HWND_BOTTOM.
402 * If parent is 0, window is unlinked from the tree.
404 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
406 WND *wndPtr = WIN_GetPtr( hwnd );
408 if (!wndPtr) return;
409 if (wndPtr == WND_OTHER_PROCESS)
411 if (IsWindow(hwnd)) ERR(" cannot link other process window %x\n", hwnd );
412 return;
415 SERVER_START_REQ( link_window )
417 req->handle = hwnd;
418 req->parent = parent;
419 req->previous = hwndInsertAfter;
420 if (!wine_server_call( req ))
422 if (reply->full_parent && reply->full_parent != wndPtr->parent)
424 wndPtr->owner = 0; /* reset owner when changing parent */
425 wndPtr->parent = reply->full_parent;
430 SERVER_END_REQ;
431 WIN_ReleasePtr( wndPtr );
435 /***********************************************************************
436 * WIN_SetOwner
438 * Change the owner of a window.
440 void WIN_SetOwner( HWND hwnd, HWND owner )
442 WND *win = WIN_GetPtr( hwnd );
444 if (!win) return;
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;
450 SERVER_START_REQ( set_window_owner )
452 req->handle = hwnd;
453 req->owner = owner;
454 if (!wine_server_call( req )) win->owner = reply->full_owner;
456 SERVER_END_REQ;
457 WIN_ReleasePtr( win );
461 /***********************************************************************
462 * WIN_SetStyle
464 * Change the style of a window.
466 LONG WIN_SetStyle( HWND hwnd, LONG style )
468 BOOL ok;
469 LONG ret = 0;
470 WND *win = WIN_GetPtr( hwnd );
472 if (!win) return 0;
473 if (win == WND_OTHER_PROCESS)
475 if (IsWindow(hwnd))
476 ERR( "cannot set style %lx on other process window %x\n", style, hwnd );
477 return 0;
479 if (style == win->dwStyle)
481 WIN_ReleasePtr( win );
482 return style;
484 SERVER_START_REQ( set_window_info )
486 req->handle = hwnd;
487 req->flags = SET_WIN_STYLE;
488 req->style = style;
489 if ((ok = !wine_server_call( req )))
491 ret = reply->old_style;
492 win->dwStyle = style;
495 SERVER_END_REQ;
496 WIN_ReleasePtr( win );
497 if (ok && USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, ret );
498 return ret;
502 /***********************************************************************
503 * WIN_SetExStyle
505 * Change the extended style of a window.
507 LONG WIN_SetExStyle( HWND hwnd, LONG style )
509 LONG ret = 0;
510 WND *win = WIN_GetPtr( hwnd );
512 if (!win) return 0;
513 if (win == WND_OTHER_PROCESS)
515 if (IsWindow(hwnd))
516 ERR( "cannot set exstyle %lx on other process window %x\n", style, hwnd );
517 return 0;
519 if (style == win->dwExStyle)
521 WIN_ReleasePtr( win );
522 return style;
524 SERVER_START_REQ( set_window_info )
526 req->handle = hwnd;
527 req->flags = SET_WIN_EXSTYLE;
528 req->ex_style = style;
529 if (!wine_server_call( req ))
531 ret = reply->old_ex_style;
532 win->dwExStyle = style;
535 SERVER_END_REQ;
536 WIN_ReleasePtr( win );
537 return ret;
541 /***********************************************************************
542 * WIN_SetRectangles
544 * Set the window and client rectangles.
546 void WIN_SetRectangles( HWND hwnd, const RECT *rectWindow, const RECT *rectClient )
548 WND *win = WIN_GetPtr( hwnd );
549 BOOL ret;
551 if (!win) return;
552 if (win == WND_OTHER_PROCESS)
554 if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %x\n", hwnd );
555 return;
557 SERVER_START_REQ( set_window_rectangles )
559 req->handle = hwnd;
560 req->window.left = rectWindow->left;
561 req->window.top = rectWindow->top;
562 req->window.right = rectWindow->right;
563 req->window.bottom = rectWindow->bottom;
564 req->client.left = rectClient->left;
565 req->client.top = rectClient->top;
566 req->client.right = rectClient->right;
567 req->client.bottom = rectClient->bottom;
568 ret = !wine_server_call( req );
570 SERVER_END_REQ;
571 if (ret)
573 win->rectWindow = *rectWindow;
574 win->rectClient = *rectClient;
576 TRACE( "win %x window (%d,%d)-(%d,%d) client (%d,%d)-(%d,%d)\n", hwnd,
577 rectWindow->left, rectWindow->top, rectWindow->right, rectWindow->bottom,
578 rectClient->left, rectClient->top, rectClient->right, rectClient->bottom );
580 WIN_ReleasePtr( win );
584 /***********************************************************************
585 * WIN_GetRectangles
587 * Get the window and client rectangles.
589 BOOL WIN_GetRectangles( HWND hwnd, RECT *rectWindow, RECT *rectClient )
591 WND *win = WIN_GetPtr( hwnd );
592 BOOL ret = TRUE;
594 if (!win) return FALSE;
595 if (win == WND_OTHER_PROCESS)
597 SERVER_START_REQ( get_window_rectangles )
599 req->handle = hwnd;
600 if ((ret = !wine_server_call( req )))
602 if (rectWindow)
604 rectWindow->left = reply->window.left;
605 rectWindow->top = reply->window.top;
606 rectWindow->right = reply->window.right;
607 rectWindow->bottom = reply->window.bottom;
609 if (rectClient)
611 rectClient->left = reply->client.left;
612 rectClient->top = reply->client.top;
613 rectClient->right = reply->client.right;
614 rectClient->bottom = reply->client.bottom;
618 SERVER_END_REQ;
620 else
622 if (rectWindow) *rectWindow = win->rectWindow;
623 if (rectClient) *rectClient = win->rectClient;
624 WIN_ReleasePtr( win );
626 return ret;
630 /***********************************************************************
631 * WIN_DestroyWindow
633 * Destroy storage associated to a window. "Internals" p.358
635 LRESULT WIN_DestroyWindow( HWND hwnd )
637 WND *wndPtr;
638 HWND *list;
640 TRACE("%04x\n", hwnd );
642 if (!(hwnd = WIN_IsCurrentThread( hwnd )))
644 ERR( "window doesn't belong to current thread\n" );
645 return 0;
648 /* free child windows */
649 if ((list = WIN_ListChildren( hwnd )))
651 int i;
652 for (i = 0; list[i]; i++)
654 if (WIN_IsCurrentThread( list[i] )) WIN_DestroyWindow( list[i] );
655 else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 );
657 HeapFree( GetProcessHeap(), 0, list );
661 * Clear the update region to make sure no WM_PAINT messages will be
662 * generated for this window while processing the WM_NCDESTROY.
664 RedrawWindow( hwnd, NULL, 0,
665 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
668 * Send the WM_NCDESTROY to the window being destroyed.
670 SendMessageA( hwnd, WM_NCDESTROY, 0, 0);
672 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
674 WINPOS_CheckInternalPos( hwnd );
675 if( hwnd == GetCapture()) ReleaseCapture();
677 /* free resources associated with the window */
679 TIMER_RemoveWindowTimers( hwnd );
681 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
682 wndPtr->hmemTaskQ = 0;
684 if (!(wndPtr->dwStyle & WS_CHILD))
686 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
687 if (menu) DestroyMenu( menu );
689 if (wndPtr->hSysMenu)
691 DestroyMenu( wndPtr->hSysMenu );
692 wndPtr->hSysMenu = 0;
694 USER_Driver.pDestroyWindow( hwnd );
695 DCE_FreeWindowDCE( hwnd ); /* Always do this to catch orphaned DCs */
696 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
697 CLASS_RemoveWindow( wndPtr->class );
698 wndPtr->class = NULL;
699 wndPtr->dwMagic = 0; /* Mark it as invalid */
700 WIN_ReleaseWndPtr( wndPtr );
701 return 0;
704 /***********************************************************************
705 * WIN_DestroyThreadWindows
707 * Destroy all children of 'wnd' owned by the current thread.
708 * Return TRUE if something was done.
710 void WIN_DestroyThreadWindows( HWND hwnd )
712 HWND *list;
713 int i;
715 if (!(list = WIN_ListChildren( hwnd ))) return;
716 for (i = 0; list[i]; i++)
718 if (WIN_IsCurrentThread( list[i] ))
719 DestroyWindow( list[i] );
720 else
721 WIN_DestroyThreadWindows( list[i] );
723 HeapFree( GetProcessHeap(), 0, list );
726 /***********************************************************************
727 * WIN_CreateDesktopWindow
729 * Create the desktop window.
731 BOOL WIN_CreateDesktopWindow(void)
733 struct tagCLASS *class;
734 HWND hwndDesktop;
735 INT wndExtra;
736 DWORD clsStyle;
737 WNDPROC winproc;
738 DCE *dce;
739 CREATESTRUCTA cs;
740 RECT rect;
742 TRACE("Creating desktop window\n");
744 if (!WINPOS_CreateInternalPosAtom() ||
745 !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
746 &wndExtra, &winproc, &clsStyle, &dce )))
747 return FALSE;
749 pWndDesktop = create_window_handle( 0, 0, LOWORD(DESKTOP_CLASS_ATOM),
750 sizeof(WND) + wndExtra - sizeof(pWndDesktop->wExtra) );
751 if (!pWndDesktop) return FALSE;
752 hwndDesktop = pWndDesktop->hwndSelf;
754 pWndDesktop->tid = 0; /* nobody owns the desktop */
755 pWndDesktop->parent = 0;
756 pWndDesktop->owner = 0;
757 pWndDesktop->class = class;
758 pWndDesktop->hInstance = 0;
759 pWndDesktop->text = NULL;
760 pWndDesktop->hmemTaskQ = 0;
761 pWndDesktop->hrgnUpdate = 0;
762 pWndDesktop->hwndLastActive = hwndDesktop;
763 pWndDesktop->dwStyle = 0;
764 pWndDesktop->dwExStyle = 0;
765 pWndDesktop->clsStyle = clsStyle;
766 pWndDesktop->dce = NULL;
767 pWndDesktop->pVScroll = NULL;
768 pWndDesktop->pHScroll = NULL;
769 pWndDesktop->wIDmenu = 0;
770 pWndDesktop->helpContext = 0;
771 pWndDesktop->flags = 0;
772 pWndDesktop->hSysMenu = 0;
773 pWndDesktop->userdata = 0;
774 pWndDesktop->winproc = winproc;
775 pWndDesktop->cbWndExtra = wndExtra;
777 cs.lpCreateParams = NULL;
778 cs.hInstance = 0;
779 cs.hMenu = 0;
780 cs.hwndParent = 0;
781 cs.x = 0;
782 cs.y = 0;
783 cs.cx = GetSystemMetrics( SM_CXSCREEN );
784 cs.cy = GetSystemMetrics( SM_CYSCREEN );
785 cs.style = pWndDesktop->dwStyle;
786 cs.dwExStyle = pWndDesktop->dwExStyle;
787 cs.lpszName = NULL;
788 cs.lpszClass = DESKTOP_CLASS_ATOM;
790 SetRect( &rect, 0, 0, cs.cx, cs.cy );
791 WIN_SetRectangles( hwndDesktop, &rect, &rect );
792 WIN_SetStyle( hwndDesktop, WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
794 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE )) return FALSE;
796 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
797 WIN_ReleaseWndPtr( pWndDesktop );
798 return TRUE;
802 /***********************************************************************
803 * WIN_FixCoordinates
805 * Fix the coordinates - Helper for WIN_CreateWindowEx.
806 * returns default show mode in sw.
807 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
809 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
811 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
812 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
814 if (cs->style & (WS_CHILD | WS_POPUP))
816 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
817 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
819 else /* overlapped window */
821 STARTUPINFOA info;
823 GetStartupInfoA( &info );
825 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
827 /* Never believe Microsoft's documentation... CreateWindowEx doc says
828 * that if an overlapped window is created with WS_VISIBLE style bit
829 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
830 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
831 * reveals that
833 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
834 * 2) it does not ignore the y parameter as the docs claim; instead, it
835 * uses it as second parameter to ShowWindow() unless y is either
836 * CW_USEDEFAULT or CW_USEDEFAULT16.
838 * The fact that we didn't do 2) caused bogus windows pop up when wine
839 * was running apps that were using this obscure feature. Example -
840 * calc.exe that comes with Win98 (only Win98, it's different from
841 * the one that comes with Win95 and NT)
843 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
844 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
845 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
848 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
850 if (info.dwFlags & STARTF_USESIZE)
852 cs->cx = info.dwXSize;
853 cs->cy = info.dwYSize;
855 else /* if no other hint from the app, pick 3/4 of the screen real estate */
857 RECT r;
858 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
859 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
860 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
865 else
867 /* neither x nor cx are default. Check the y values .
868 * In the trace we see Outlook and Outlook Express using
869 * cy set to CW_USEDEFAULT when opening the address book.
871 if (cs->cy == CW_USEDEFAULT || cs->cy == CW_USEDEFAULT16) {
872 RECT r;
873 FIXME("Strange use of CW_USEDEFAULT in nHeight\n");
874 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
875 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
880 /***********************************************************************
881 * dump_window_styles
883 static void dump_window_styles( DWORD style, DWORD exstyle )
885 TRACE( "style:" );
886 if(style & WS_POPUP) DPRINTF(" WS_POPUP");
887 if(style & WS_CHILD) DPRINTF(" WS_CHILD");
888 if(style & WS_MINIMIZE) DPRINTF(" WS_MINIMIZE");
889 if(style & WS_VISIBLE) DPRINTF(" WS_VISIBLE");
890 if(style & WS_DISABLED) DPRINTF(" WS_DISABLED");
891 if(style & WS_CLIPSIBLINGS) DPRINTF(" WS_CLIPSIBLINGS");
892 if(style & WS_CLIPCHILDREN) DPRINTF(" WS_CLIPCHILDREN");
893 if(style & WS_MAXIMIZE) DPRINTF(" WS_MAXIMIZE");
894 if((style & WS_CAPTION) == WS_CAPTION) DPRINTF(" WS_CAPTION");
895 else
897 if(style & WS_BORDER) DPRINTF(" WS_BORDER");
898 if(style & WS_DLGFRAME) DPRINTF(" WS_DLGFRAME");
900 if(style & WS_VSCROLL) DPRINTF(" WS_VSCROLL");
901 if(style & WS_HSCROLL) DPRINTF(" WS_HSCROLL");
902 if(style & WS_SYSMENU) DPRINTF(" WS_SYSMENU");
903 if(style & WS_THICKFRAME) DPRINTF(" WS_THICKFRAME");
904 if(style & WS_GROUP) DPRINTF(" WS_GROUP");
905 if(style & WS_TABSTOP) DPRINTF(" WS_TABSTOP");
906 if(style & WS_MINIMIZEBOX) DPRINTF(" WS_MINIMIZEBOX");
907 if(style & WS_MAXIMIZEBOX) DPRINTF(" WS_MAXIMIZEBOX");
909 /* FIXME: Add dumping of BS_/ES_/SBS_/LBS_/CBS_/DS_/etc. styles */
910 #define DUMPED_STYLES \
911 (WS_POPUP | \
912 WS_CHILD | \
913 WS_MINIMIZE | \
914 WS_VISIBLE | \
915 WS_DISABLED | \
916 WS_CLIPSIBLINGS | \
917 WS_CLIPCHILDREN | \
918 WS_MAXIMIZE | \
919 WS_BORDER | \
920 WS_DLGFRAME | \
921 WS_VSCROLL | \
922 WS_HSCROLL | \
923 WS_SYSMENU | \
924 WS_THICKFRAME | \
925 WS_GROUP | \
926 WS_TABSTOP | \
927 WS_MINIMIZEBOX | \
928 WS_MAXIMIZEBOX)
930 if(style & ~DUMPED_STYLES) DPRINTF(" %08lx", style & ~DUMPED_STYLES);
931 DPRINTF("\n");
932 #undef DUMPED_STYLES
934 TRACE( "exstyle:" );
935 if(exstyle & WS_EX_DLGMODALFRAME) DPRINTF(" WS_EX_DLGMODALFRAME");
936 if(exstyle & WS_EX_DRAGDETECT) DPRINTF(" WS_EX_DRAGDETECT");
937 if(exstyle & WS_EX_NOPARENTNOTIFY) DPRINTF(" WS_EX_NOPARENTNOTIFY");
938 if(exstyle & WS_EX_TOPMOST) DPRINTF(" WS_EX_TOPMOST");
939 if(exstyle & WS_EX_ACCEPTFILES) DPRINTF(" WS_EX_ACCEPTFILES");
940 if(exstyle & WS_EX_TRANSPARENT) DPRINTF(" WS_EX_TRANSPARENT");
941 if(exstyle & WS_EX_MDICHILD) DPRINTF(" WS_EX_MDICHILD");
942 if(exstyle & WS_EX_TOOLWINDOW) DPRINTF(" WS_EX_TOOLWINDOW");
943 if(exstyle & WS_EX_WINDOWEDGE) DPRINTF(" WS_EX_WINDOWEDGE");
944 if(exstyle & WS_EX_CLIENTEDGE) DPRINTF(" WS_EX_CLIENTEDGE");
945 if(exstyle & WS_EX_CONTEXTHELP) DPRINTF(" WS_EX_CONTEXTHELP");
946 if(exstyle & WS_EX_RIGHT) DPRINTF(" WS_EX_RIGHT");
947 if(exstyle & WS_EX_RTLREADING) DPRINTF(" WS_EX_RTLREADING");
948 if(exstyle & WS_EX_LEFTSCROLLBAR) DPRINTF(" WS_EX_LEFTSCROLLBAR");
949 if(exstyle & WS_EX_CONTROLPARENT) DPRINTF(" WS_EX_CONTROLPARENT");
950 if(exstyle & WS_EX_STATICEDGE) DPRINTF(" WS_EX_STATICEDGE");
951 if(exstyle & WS_EX_APPWINDOW) DPRINTF(" WS_EX_APPWINDOW");
952 if(exstyle & WS_EX_LAYERED) DPRINTF(" WS_EX_LAYERED");
954 #define DUMPED_EX_STYLES \
955 (WS_EX_DLGMODALFRAME | \
956 WS_EX_DRAGDETECT | \
957 WS_EX_NOPARENTNOTIFY | \
958 WS_EX_TOPMOST | \
959 WS_EX_ACCEPTFILES | \
960 WS_EX_TRANSPARENT | \
961 WS_EX_MDICHILD | \
962 WS_EX_TOOLWINDOW | \
963 WS_EX_WINDOWEDGE | \
964 WS_EX_CLIENTEDGE | \
965 WS_EX_CONTEXTHELP | \
966 WS_EX_RIGHT | \
967 WS_EX_RTLREADING | \
968 WS_EX_LEFTSCROLLBAR | \
969 WS_EX_CONTROLPARENT | \
970 WS_EX_STATICEDGE | \
971 WS_EX_APPWINDOW | \
972 WS_EX_LAYERED)
974 if(exstyle & ~DUMPED_EX_STYLES) DPRINTF(" %08lx", exstyle & ~DUMPED_EX_STYLES);
975 DPRINTF("\n");
976 #undef DUMPED_EX_STYLES
980 /***********************************************************************
981 * WIN_CreateWindowEx
983 * Implementation of CreateWindowEx().
985 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
986 WINDOWPROCTYPE type )
988 INT sw = SW_SHOW;
989 struct tagCLASS *classPtr;
990 WND *wndPtr;
991 HWND hwnd, parent, owner;
992 INT wndExtra;
993 DWORD clsStyle;
994 WNDPROC winproc;
995 DCE *dce;
996 BOOL unicode = (type == WIN_PROC_32W);
998 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%04x menu=%04x inst=%08x params=%p\n",
999 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszName) : debugres_a(cs->lpszName),
1000 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszClass) : debugres_a(cs->lpszClass),
1001 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
1002 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
1004 if(TRACE_ON(win)) dump_window_styles( cs->style, cs->dwExStyle );
1006 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
1007 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
1009 /* Find the parent window */
1011 parent = GetDesktopWindow();
1012 owner = 0;
1013 if (cs->hwndParent)
1015 /* Make sure parent is valid */
1016 if (!IsWindow( cs->hwndParent ))
1018 WARN("Bad parent %04x\n", cs->hwndParent );
1019 return 0;
1021 if (cs->style & WS_CHILD) parent = WIN_GetFullHandle(cs->hwndParent);
1022 else owner = GetAncestor( cs->hwndParent, GA_ROOT );
1024 else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP))
1026 WARN("No parent for child window\n" );
1027 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
1030 /* Find the window class */
1031 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
1032 &wndExtra, &winproc, &clsStyle, &dce )))
1034 WARN("Bad class '%s'\n", cs->lpszClass );
1035 return 0;
1038 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
1040 /* Correct the window style - stage 1
1042 * These are patches that appear to affect both the style loaded into the
1043 * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
1045 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1046 * why does the user get to set it?
1049 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
1050 * tested for WS_POPUP
1052 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
1053 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
1054 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
1055 cs->dwExStyle |= WS_EX_WINDOWEDGE;
1056 else
1057 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
1059 /* Create the window structure */
1061 if (!(wndPtr = create_window_handle( parent, owner, classAtom,
1062 sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
1064 TRACE("out of memory\n" );
1065 return 0;
1067 hwnd = wndPtr->hwndSelf;
1069 /* Fill the window structure */
1071 wndPtr->tid = GetCurrentThreadId();
1072 wndPtr->owner = owner;
1073 wndPtr->parent = parent;
1074 wndPtr->class = classPtr;
1075 wndPtr->winproc = winproc;
1076 wndPtr->hInstance = cs->hInstance;
1077 wndPtr->text = NULL;
1078 wndPtr->hmemTaskQ = InitThreadInput16( 0, 0 );
1079 wndPtr->hrgnUpdate = 0;
1080 wndPtr->hrgnWnd = 0;
1081 wndPtr->hwndLastActive = hwnd;
1082 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
1083 wndPtr->dwExStyle = cs->dwExStyle;
1084 wndPtr->clsStyle = clsStyle;
1085 wndPtr->wIDmenu = 0;
1086 wndPtr->helpContext = 0;
1087 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
1088 wndPtr->pVScroll = NULL;
1089 wndPtr->pHScroll = NULL;
1090 wndPtr->userdata = 0;
1091 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU)
1092 ? MENU_GetSysMenu( hwnd, 0 ) : 0;
1093 wndPtr->cbWndExtra = wndExtra;
1095 if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
1097 /* Correct the window style - stage 2 */
1099 if (!(cs->style & WS_CHILD))
1101 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
1102 if (!(cs->style & WS_POPUP))
1104 wndPtr->dwStyle |= WS_CAPTION;
1105 wndPtr->flags |= WIN_NEED_SIZE;
1108 SERVER_START_REQ( set_window_info )
1110 req->handle = hwnd;
1111 req->flags = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE;
1112 req->style = wndPtr->dwStyle;
1113 req->ex_style = wndPtr->dwExStyle;
1114 req->instance = (void *)wndPtr->hInstance;
1115 wine_server_call( req );
1117 SERVER_END_REQ;
1119 /* Get class or window DC if needed */
1121 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
1122 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
1123 else wndPtr->dce = NULL;
1125 /* Set the window menu */
1127 if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
1129 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
1130 else
1132 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
1133 if (menuName)
1135 if (HIWORD(cs->hInstance))
1136 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
1137 else
1138 cs->hMenu = LoadMenu16(cs->hInstance,menuName);
1140 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
1144 else SetWindowLongW( hwnd, GWL_ID, (UINT)cs->hMenu );
1145 WIN_ReleaseWndPtr( wndPtr );
1147 if (!USER_Driver.pCreateWindow( hwnd, cs, unicode))
1149 WIN_DestroyWindow( hwnd );
1150 return 0;
1153 /* Notify the parent window only */
1155 send_parent_notify( hwnd, WM_CREATE );
1156 if (!IsWindow( hwnd )) return 0;
1158 if (cs->style & WS_VISIBLE)
1160 /* in case WS_VISIBLE got set in the meantime */
1161 if (!(wndPtr = WIN_GetPtr( hwnd ))) return 0;
1162 WIN_SetStyle( hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
1163 WIN_ReleasePtr( wndPtr );
1164 ShowWindow( hwnd, sw );
1167 /* Call WH_SHELL hook */
1169 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1170 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
1172 TRACE("created window %04x\n", hwnd);
1173 return hwnd;
1177 /***********************************************************************
1178 * CreateWindow (USER.41)
1180 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1181 DWORD style, INT16 x, INT16 y, INT16 width,
1182 INT16 height, HWND16 parent, HMENU16 menu,
1183 HINSTANCE16 instance, LPVOID data )
1185 return CreateWindowEx16( 0, className, windowName, style,
1186 x, y, width, height, parent, menu, instance, data );
1190 /***********************************************************************
1191 * CreateWindowEx (USER.452)
1193 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1194 LPCSTR windowName, DWORD style, INT16 x,
1195 INT16 y, INT16 width, INT16 height,
1196 HWND16 parent, HMENU16 menu,
1197 HINSTANCE16 instance, LPVOID data )
1199 ATOM classAtom;
1200 CREATESTRUCTA cs;
1201 char buffer[256];
1203 /* Find the class atom */
1205 if (HIWORD(className))
1207 if (!(classAtom = GlobalFindAtomA( className )))
1209 ERR( "bad class name %s\n", debugres_a(className) );
1210 return 0;
1213 else
1215 classAtom = LOWORD(className);
1216 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1218 ERR( "bad atom %x\n", classAtom);
1219 return 0;
1221 className = buffer;
1224 /* Fix the coordinates */
1226 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1227 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1228 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1229 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1231 /* Create the window */
1233 cs.lpCreateParams = data;
1234 cs.hInstance = (HINSTANCE)instance;
1235 cs.hMenu = (HMENU)menu;
1236 cs.hwndParent = WIN_Handle32( parent );
1237 cs.style = style;
1238 cs.lpszName = windowName;
1239 cs.lpszClass = className;
1240 cs.dwExStyle = exStyle;
1242 return WIN_Handle16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1246 /***********************************************************************
1247 * CreateWindowExA (USER32.@)
1249 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1250 LPCSTR windowName, DWORD style, INT x,
1251 INT y, INT width, INT height,
1252 HWND parent, HMENU menu,
1253 HINSTANCE instance, LPVOID data )
1255 ATOM classAtom;
1256 CREATESTRUCTA cs;
1257 char buffer[256];
1259 if(!instance)
1260 instance=GetModuleHandleA(NULL);
1262 if(exStyle & WS_EX_MDICHILD)
1263 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1265 /* Find the class atom */
1267 if (HIWORD(className))
1269 if (!(classAtom = GlobalFindAtomA( className )))
1271 ERR( "bad class name %s\n", debugres_a(className) );
1272 return 0;
1275 else
1277 classAtom = LOWORD(className);
1278 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1280 ERR( "bad atom %x\n", classAtom);
1281 return 0;
1283 className = buffer;
1286 /* Create the window */
1288 cs.lpCreateParams = data;
1289 cs.hInstance = instance;
1290 cs.hMenu = menu;
1291 cs.hwndParent = parent;
1292 cs.x = x;
1293 cs.y = y;
1294 cs.cx = width;
1295 cs.cy = height;
1296 cs.style = style;
1297 cs.lpszName = windowName;
1298 cs.lpszClass = className;
1299 cs.dwExStyle = exStyle;
1301 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1305 /***********************************************************************
1306 * CreateWindowExW (USER32.@)
1308 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1309 LPCWSTR windowName, DWORD style, INT x,
1310 INT y, INT width, INT height,
1311 HWND parent, HMENU menu,
1312 HINSTANCE instance, LPVOID data )
1314 ATOM classAtom;
1315 CREATESTRUCTW cs;
1316 WCHAR buffer[256];
1318 if(!instance)
1319 instance=GetModuleHandleA(NULL);
1321 if(exStyle & WS_EX_MDICHILD)
1322 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1324 /* Find the class atom */
1326 if (HIWORD(className))
1328 if (!(classAtom = GlobalFindAtomW( className )))
1330 ERR( "bad class name %s\n", debugres_w(className) );
1331 return 0;
1334 else
1336 classAtom = LOWORD(className);
1337 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1339 ERR( "bad atom %x\n", classAtom);
1340 return 0;
1342 className = buffer;
1345 /* Create the window */
1347 cs.lpCreateParams = data;
1348 cs.hInstance = instance;
1349 cs.hMenu = menu;
1350 cs.hwndParent = parent;
1351 cs.x = x;
1352 cs.y = y;
1353 cs.cx = width;
1354 cs.cy = height;
1355 cs.style = style;
1356 cs.lpszName = windowName;
1357 cs.lpszClass = className;
1358 cs.dwExStyle = exStyle;
1360 /* Note: we rely on the fact that CREATESTRUCTA and */
1361 /* CREATESTRUCTW have the same layout. */
1362 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1366 /***********************************************************************
1367 * WIN_SendDestroyMsg
1369 static void WIN_SendDestroyMsg( HWND hwnd )
1371 if( CARET_GetHwnd() == hwnd) DestroyCaret();
1372 if (USER_Driver.pResetSelectionOwner)
1373 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1376 * Send the WM_DESTROY to the window.
1378 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1381 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1382 * make sure that the window still exists when we come back.
1384 if (IsWindow(hwnd))
1386 HWND* pWndArray;
1387 int i;
1389 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1391 /* start from the end (FIXME: is this needed?) */
1392 for (i = 0; pWndArray[i]; i++) ;
1394 while (--i >= 0)
1396 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1398 HeapFree( GetProcessHeap(), 0, pWndArray );
1400 else
1401 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1405 /***********************************************************************
1406 * DestroyWindow (USER32.@)
1408 BOOL WINAPI DestroyWindow( HWND hwnd )
1410 BOOL is_child;
1411 HWND h;
1413 if (!(hwnd = WIN_IsCurrentThread( hwnd )) || (hwnd == GetDesktopWindow()))
1415 SetLastError( ERROR_ACCESS_DENIED );
1416 return FALSE;
1419 TRACE("(%04x)\n", hwnd);
1421 /* Look whether the focus is within the tree of windows we will
1422 * be destroying.
1424 h = GetFocus();
1425 if (h == hwnd || IsChild( hwnd, h ))
1427 HWND parent = GetAncestor( hwnd, GA_PARENT );
1428 if (parent == GetDesktopWindow()) parent = 0;
1429 SetFocus( parent );
1432 /* Call hooks */
1434 if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
1436 is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1438 if (is_child)
1440 if (!USER_IsExitingThread( GetCurrentThreadId() ))
1441 send_parent_notify( hwnd, WM_DESTROY );
1443 else if (!GetWindow( hwnd, GW_OWNER ))
1445 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
1446 /* FIXME: clean up palette - see "Internals" p.352 */
1449 if (!IsWindow(hwnd)) return TRUE;
1451 if (USER_Driver.pResetSelectionOwner)
1452 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1454 /* Hide the window */
1456 ShowWindow( hwnd, SW_HIDE );
1457 if (!IsWindow(hwnd)) return TRUE;
1459 /* Recursively destroy owned windows */
1461 if (!is_child)
1463 HWND owner;
1465 for (;;)
1467 int i, got_one = 0;
1468 HWND *list = WIN_ListChildren( GetDesktopWindow() );
1469 if (list)
1471 for (i = 0; list[i]; i++)
1473 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1474 if (WIN_IsCurrentThread( list[i] ))
1476 DestroyWindow( list[i] );
1477 got_one = 1;
1478 continue;
1480 WIN_SetOwner( list[i], 0 );
1482 HeapFree( GetProcessHeap(), 0, list );
1484 if (!got_one) break;
1487 WINPOS_ActivateOtherWindow( hwnd );
1489 if ((owner = GetWindow( hwnd, GW_OWNER )))
1491 WND *ptr = WIN_FindWndPtr( owner );
1492 if (ptr)
1494 if (ptr->hwndLastActive == hwnd) ptr->hwndLastActive = owner;
1495 WIN_ReleaseWndPtr( ptr );
1500 /* Send destroy messages */
1502 WIN_SendDestroyMsg( hwnd );
1503 if (!IsWindow( hwnd )) return TRUE;
1505 /* Unlink now so we won't bother with the children later on */
1507 WIN_UnlinkWindow( hwnd );
1509 /* Destroy the window storage */
1511 WIN_DestroyWindow( hwnd );
1512 return TRUE;
1516 /***********************************************************************
1517 * CloseWindow (USER32.@)
1519 BOOL WINAPI CloseWindow( HWND hwnd )
1521 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1522 ShowWindow( hwnd, SW_MINIMIZE );
1523 return TRUE;
1527 /***********************************************************************
1528 * OpenIcon (USER32.@)
1530 BOOL WINAPI OpenIcon( HWND hwnd )
1532 if (!IsIconic( hwnd )) return FALSE;
1533 ShowWindow( hwnd, SW_SHOWNORMAL );
1534 return TRUE;
1538 /***********************************************************************
1539 * WIN_FindWindow
1541 * Implementation of FindWindow() and FindWindowEx().
1543 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1545 HWND *list = NULL;
1546 HWND retvalue = 0;
1547 int i = 0, len = 0;
1548 WCHAR *buffer = NULL;
1550 if (!parent) parent = GetDesktopWindow();
1551 if (title)
1553 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1554 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1557 if (!(list = list_window_children( parent, className, 0 ))) goto done;
1559 if (child)
1561 child = WIN_GetFullHandle( child );
1562 while (list[i] && list[i] != child) i++;
1563 if (!list[i]) goto done;
1564 i++; /* start from next window */
1567 if (title)
1569 while (list[i])
1571 if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1572 i++;
1575 retvalue = list[i];
1577 done:
1578 if (list) HeapFree( GetProcessHeap(), 0, list );
1579 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1580 return retvalue;
1585 /***********************************************************************
1586 * FindWindowA (USER32.@)
1588 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1590 HWND ret = FindWindowExA( 0, 0, className, title );
1591 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1592 return ret;
1596 /***********************************************************************
1597 * FindWindowExA (USER32.@)
1599 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1600 LPCSTR className, LPCSTR title )
1602 ATOM atom = 0;
1603 LPWSTR buffer;
1604 HWND hwnd;
1605 INT len;
1607 if (className)
1609 /* If the atom doesn't exist, then no class */
1610 /* with this name exists either. */
1611 if (!(atom = GlobalFindAtomA( className )))
1613 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1614 return 0;
1617 if (!title) return WIN_FindWindow( parent, child, atom, NULL );
1619 len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1620 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1621 MultiByteToWideChar( CP_ACP, 0, title, -1, buffer, len );
1622 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1623 HeapFree( GetProcessHeap(), 0, buffer );
1624 return hwnd;
1628 /***********************************************************************
1629 * FindWindowExW (USER32.@)
1631 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1632 LPCWSTR className, LPCWSTR title )
1634 ATOM atom = 0;
1636 if (className)
1638 /* If the atom doesn't exist, then no class */
1639 /* with this name exists either. */
1640 if (!(atom = GlobalFindAtomW( className )))
1642 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1643 return 0;
1646 return WIN_FindWindow( parent, child, atom, title );
1650 /***********************************************************************
1651 * FindWindowW (USER32.@)
1653 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1655 return FindWindowExW( 0, 0, className, title );
1659 /**********************************************************************
1660 * GetDesktopWindow (USER32.@)
1662 HWND WINAPI GetDesktopWindow(void)
1664 if (pWndDesktop) return pWndDesktop->hwndSelf;
1665 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" );
1666 ExitProcess(1);
1667 return 0;
1671 /*******************************************************************
1672 * EnableWindow (USER32.@)
1674 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1676 WND *wndPtr;
1677 BOOL retvalue;
1678 LONG style;
1679 HWND full_handle;
1681 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1682 return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1684 hwnd = full_handle;
1686 TRACE("( %x, %d )\n", hwnd, enable);
1688 if (!(wndPtr = WIN_GetPtr( hwnd ))) return FALSE;
1689 style = wndPtr->dwStyle;
1690 retvalue = ((style & WS_DISABLED) != 0);
1691 WIN_ReleasePtr( wndPtr );
1693 if (enable && retvalue)
1695 WIN_SetStyle( hwnd, style & ~WS_DISABLED );
1696 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1698 else if (!enable && !retvalue)
1700 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1702 WIN_SetStyle( hwnd, style | WS_DISABLED );
1704 if (hwnd == GetFocus())
1705 SetFocus( 0 ); /* A disabled window can't have the focus */
1707 if (hwnd == GetCapture())
1708 ReleaseCapture(); /* A disabled window can't capture the mouse */
1710 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1712 return retvalue;
1716 /***********************************************************************
1717 * IsWindowEnabled (USER32.@)
1719 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1721 return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1725 /***********************************************************************
1726 * IsWindowUnicode (USER32.@)
1728 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1730 WND * wndPtr;
1731 BOOL retvalue;
1733 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1734 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1735 WIN_ReleaseWndPtr(wndPtr);
1736 return retvalue;
1740 /**********************************************************************
1741 * GetWindowWord (USER32.@)
1743 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1745 if (offset >= 0)
1747 WORD retvalue = 0;
1748 WND *wndPtr = WIN_GetPtr( hwnd );
1749 if (!wndPtr)
1751 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1752 return 0;
1754 if (wndPtr == WND_OTHER_PROCESS)
1756 if (IsWindow( hwnd ))
1757 FIXME( "(%d) not supported yet on other process window %x\n", offset, hwnd );
1758 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1759 return 0;
1761 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1763 WARN("Invalid offset %d\n", offset );
1764 SetLastError( ERROR_INVALID_INDEX );
1766 else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1767 WIN_ReleasePtr( wndPtr );
1768 return retvalue;
1771 switch(offset)
1773 case GWL_HWNDPARENT:
1774 return GetWindowLongW( hwnd, offset );
1775 case GWL_ID:
1776 case GWL_HINSTANCE:
1778 LONG ret = GetWindowLongW( hwnd, offset );
1779 if (HIWORD(ret))
1780 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1781 return LOWORD(ret);
1783 default:
1784 WARN("Invalid offset %d\n", offset );
1785 return 0;
1790 /**********************************************************************
1791 * SetWindowWord (USER32.@)
1793 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1795 WORD *ptr, retval;
1796 WND * wndPtr;
1798 switch(offset)
1800 case GWL_ID:
1801 case GWL_HINSTANCE:
1802 case GWL_HWNDPARENT:
1803 return SetWindowLongW( hwnd, offset, (UINT)newval );
1804 default:
1805 if (offset < 0)
1807 WARN("Invalid offset %d\n", offset );
1808 SetLastError( ERROR_INVALID_INDEX );
1809 return 0;
1813 wndPtr = WIN_GetPtr( hwnd );
1814 if (wndPtr == WND_OTHER_PROCESS)
1816 if (IsWindow(hwnd))
1817 FIXME( "set %d <- %x not supported yet on other process window %x\n",
1818 offset, newval, hwnd );
1819 wndPtr = NULL;
1821 if (!wndPtr)
1823 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1824 return 0;
1827 if (offset > wndPtr->cbWndExtra - sizeof(WORD))
1829 WARN("Invalid offset %d\n", offset );
1830 WIN_ReleasePtr(wndPtr);
1831 SetLastError( ERROR_INVALID_INDEX );
1832 return 0;
1834 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1835 retval = *ptr;
1836 *ptr = newval;
1837 WIN_ReleasePtr(wndPtr);
1838 return retval;
1842 /**********************************************************************
1843 * WIN_GetWindowLong
1845 * Helper function for GetWindowLong().
1847 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1849 LONG retvalue = 0;
1850 WND *wndPtr;
1852 if (offset == GWL_HWNDPARENT) return (LONG)GetParent( hwnd );
1854 if (!(wndPtr = WIN_GetPtr( hwnd )))
1856 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1857 return 0;
1860 if (wndPtr == WND_OTHER_PROCESS)
1862 if (offset >= 0)
1864 if (IsWindow(hwnd))
1865 FIXME( "(%d) not supported on other process window %x\n", offset, hwnd );
1866 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1867 return 0;
1869 if (offset == GWL_WNDPROC)
1871 SetLastError( ERROR_ACCESS_DENIED );
1872 return 0;
1874 SERVER_START_REQ( set_window_info )
1876 req->handle = hwnd;
1877 req->flags = 0; /* don't set anything, just retrieve */
1878 if (!wine_server_call_err( req ))
1880 switch(offset)
1882 case GWL_STYLE: retvalue = reply->old_style; break;
1883 case GWL_EXSTYLE: retvalue = reply->old_ex_style; break;
1884 case GWL_ID: retvalue = reply->old_id; break;
1885 case GWL_HINSTANCE: retvalue = (ULONG_PTR)reply->old_instance; break;
1886 case GWL_USERDATA: retvalue = (ULONG_PTR)reply->old_user_data; break;
1887 default:
1888 SetLastError( ERROR_INVALID_INDEX );
1889 break;
1893 SERVER_END_REQ;
1894 return retvalue;
1897 /* now we have a valid wndPtr */
1899 if (offset >= 0)
1901 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1904 * Some programs try to access last element from 16 bit
1905 * code using illegal offset value. Hopefully this is
1906 * what those programs really expect.
1908 if (type == WIN_PROC_16 &&
1909 wndPtr->cbWndExtra >= 4 &&
1910 offset == wndPtr->cbWndExtra - sizeof(WORD))
1912 INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
1914 ERR( "- replaced invalid offset %d with %d\n",
1915 offset, offset2 );
1917 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset2);
1918 WIN_ReleasePtr( wndPtr );
1919 return retvalue;
1921 WARN("Invalid offset %d\n", offset );
1922 WIN_ReleasePtr( wndPtr );
1923 SetLastError( ERROR_INVALID_INDEX );
1924 return 0;
1926 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1927 /* Special case for dialog window procedure */
1928 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1929 retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1930 WIN_ReleasePtr( wndPtr );
1931 return retvalue;
1934 switch(offset)
1936 case GWL_USERDATA: retvalue = wndPtr->userdata; break;
1937 case GWL_STYLE: retvalue = wndPtr->dwStyle; break;
1938 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle; break;
1939 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu; break;
1940 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1941 case GWL_HINSTANCE: retvalue = wndPtr->hInstance; break;
1942 default:
1943 WARN("Unknown offset %d\n", offset );
1944 SetLastError( ERROR_INVALID_INDEX );
1945 break;
1947 WIN_ReleasePtr(wndPtr);
1948 return retvalue;
1952 /**********************************************************************
1953 * WIN_SetWindowLong
1955 * Helper function for SetWindowLong().
1957 * 0 is the failure code. However, in the case of failure SetLastError
1958 * must be set to distinguish between a 0 return value and a failure.
1960 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1961 WINDOWPROCTYPE type )
1963 LONG retval = 0;
1964 WND *wndPtr;
1966 TRACE( "%x %d %lx %x\n", hwnd, offset, newval, type );
1968 if (!WIN_IsCurrentProcess( hwnd ))
1970 if (offset == GWL_WNDPROC)
1972 SetLastError( ERROR_ACCESS_DENIED );
1973 return 0;
1975 return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1978 wndPtr = WIN_GetPtr( hwnd );
1980 if (offset >= 0)
1982 LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1983 if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1985 WARN("Invalid offset %d\n", offset );
1986 WIN_ReleasePtr( wndPtr );
1987 SetLastError( ERROR_INVALID_INDEX );
1988 return 0;
1990 /* Special case for dialog window procedure */
1991 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1993 retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1994 WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
1995 type, WIN_PROC_WINDOW );
1996 WIN_ReleasePtr( wndPtr );
1997 return retval;
1999 retval = *ptr;
2000 *ptr = newval;
2001 WIN_ReleasePtr( wndPtr );
2003 else
2005 STYLESTRUCT style;
2006 BOOL ok;
2008 /* first some special cases */
2009 switch( offset )
2011 case GWL_STYLE:
2012 case GWL_EXSTYLE:
2013 style.styleOld = wndPtr->dwStyle;
2014 style.styleNew = newval;
2015 WIN_ReleasePtr( wndPtr );
2016 SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
2017 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2018 newval = style.styleNew;
2019 break;
2020 case GWL_HWNDPARENT:
2021 WIN_ReleasePtr( wndPtr );
2022 return (LONG)SetParent( hwnd, (HWND)newval );
2023 case GWL_WNDPROC:
2024 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2025 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
2026 type, WIN_PROC_WINDOW );
2027 WIN_ReleasePtr( wndPtr );
2028 return retval;
2029 case GWL_ID:
2030 case GWL_HINSTANCE:
2031 case GWL_USERDATA:
2032 break;
2033 default:
2034 WIN_ReleasePtr( wndPtr );
2035 WARN("Invalid offset %d\n", offset );
2036 SetLastError( ERROR_INVALID_INDEX );
2037 return 0;
2040 SERVER_START_REQ( set_window_info )
2042 req->handle = hwnd;
2043 switch(offset)
2045 case GWL_STYLE:
2046 req->flags = SET_WIN_STYLE;
2047 req->style = newval;
2048 break;
2049 case GWL_EXSTYLE:
2050 req->flags = SET_WIN_EXSTYLE;
2051 req->ex_style = newval;
2052 break;
2053 case GWL_ID:
2054 req->flags = SET_WIN_ID;
2055 req->id = newval;
2056 break;
2057 case GWL_HINSTANCE:
2058 req->flags = SET_WIN_INSTANCE;
2059 req->instance = (void *)newval;
2060 break;
2061 case GWL_USERDATA:
2062 req->flags = SET_WIN_USERDATA;
2063 req->user_data = (void *)newval;
2064 break;
2066 if ((ok = !wine_server_call_err( req )))
2068 switch(offset)
2070 case GWL_STYLE:
2071 wndPtr->dwStyle = newval;
2072 retval = reply->old_style;
2073 break;
2074 case GWL_EXSTYLE:
2075 wndPtr->dwExStyle = newval;
2076 retval = reply->old_ex_style;
2077 break;
2078 case GWL_ID:
2079 wndPtr->wIDmenu = newval;
2080 retval = reply->old_id;
2081 break;
2082 case GWL_HINSTANCE:
2083 wndPtr->hInstance = newval;
2084 retval = (HINSTANCE)reply->old_instance;
2085 break;
2086 case GWL_USERDATA:
2087 wndPtr->userdata = newval;
2088 retval = (ULONG_PTR)reply->old_user_data;
2089 break;
2093 SERVER_END_REQ;
2094 WIN_ReleasePtr( wndPtr );
2096 if (!ok) return 0;
2098 if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2099 USER_Driver.pSetWindowStyle( hwnd, retval );
2101 if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2102 SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2105 return retval;
2109 /**********************************************************************
2110 * GetWindowLong (USER.135)
2112 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2114 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2118 /**********************************************************************
2119 * GetWindowLongA (USER32.@)
2121 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2123 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2127 /**********************************************************************
2128 * GetWindowLongW (USER32.@)
2130 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2132 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2136 /**********************************************************************
2137 * SetWindowLong (USER.136)
2139 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2141 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2145 /**********************************************************************
2146 * SetWindowLongA (USER32.@)
2148 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2150 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2154 /**********************************************************************
2155 * SetWindowLongW (USER32.@) Set window attribute
2157 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2158 * value in a window's extra memory.
2160 * The _hwnd_ parameter specifies the window. is the handle to a
2161 * window that has extra memory. The _newval_ parameter contains the
2162 * new attribute or extra memory value. If positive, the _offset_
2163 * parameter is the byte-addressed location in the window's extra
2164 * memory to set. If negative, _offset_ specifies the window
2165 * attribute to set, and should be one of the following values:
2167 * GWL_EXSTYLE The window's extended window style
2169 * GWL_STYLE The window's window style.
2171 * GWL_WNDPROC Pointer to the window's window procedure.
2173 * GWL_HINSTANCE The window's pplication instance handle.
2175 * GWL_ID The window's identifier.
2177 * GWL_USERDATA The window's user-specified data.
2179 * If the window is a dialog box, the _offset_ parameter can be one of
2180 * the following values:
2182 * DWL_DLGPROC The address of the window's dialog box procedure.
2184 * DWL_MSGRESULT The return value of a message
2185 * that the dialog box procedure processed.
2187 * DWL_USER Application specific information.
2189 * RETURNS
2191 * If successful, returns the previous value located at _offset_. Otherwise,
2192 * returns 0.
2194 * NOTES
2196 * Extra memory for a window class is specified by a nonzero cbWndExtra
2197 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2198 * time of class creation.
2200 * Using GWL_WNDPROC to set a new window procedure effectively creates
2201 * a window subclass. Use CallWindowProc() in the new windows procedure
2202 * to pass messages to the superclass's window procedure.
2204 * The user data is reserved for use by the application which created
2205 * the window.
2207 * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2208 * instead, call the EnableWindow() function to change the window's
2209 * disabled state.
2211 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2212 * SetParent() instead.
2214 * Win95:
2215 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2216 * it sends WM_STYLECHANGING before changing the settings
2217 * and WM_STYLECHANGED afterwards.
2218 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2220 LONG WINAPI SetWindowLongW(
2221 HWND hwnd, /* [in] window to alter */
2222 INT offset, /* [in] offset, in bytes, of location to alter */
2223 LONG newval /* [in] new value of location */
2225 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2229 /*******************************************************************
2230 * GetWindowTextA (USER32.@)
2232 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2234 WCHAR *buffer;
2236 if (WIN_IsCurrentProcess( hwnd ))
2237 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2239 /* when window belongs to other process, don't send a message */
2240 if (nMaxCount <= 0) return 0;
2241 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2242 get_server_window_text( hwnd, buffer, nMaxCount );
2243 if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2244 lpString[nMaxCount-1] = 0;
2245 HeapFree( GetProcessHeap(), 0, buffer );
2246 return strlen(lpString);
2250 /*******************************************************************
2251 * InternalGetWindowText (USER32.@)
2253 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2255 WND *win;
2257 if (nMaxCount <= 0) return 0;
2258 if (!(win = WIN_GetPtr( hwnd ))) return 0;
2259 if (win != WND_OTHER_PROCESS)
2261 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2262 else lpString[0] = 0;
2263 WIN_ReleasePtr( win );
2265 else
2267 get_server_window_text( hwnd, lpString, nMaxCount );
2269 return strlenW(lpString);
2273 /*******************************************************************
2274 * GetWindowTextW (USER32.@)
2276 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2278 if (WIN_IsCurrentProcess( hwnd ))
2279 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2281 /* when window belongs to other process, don't send a message */
2282 if (nMaxCount <= 0) return 0;
2283 get_server_window_text( hwnd, lpString, nMaxCount );
2284 return strlenW(lpString);
2288 /*******************************************************************
2289 * SetWindowText (USER32.@)
2290 * SetWindowTextA (USER32.@)
2292 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2294 if (!WIN_IsCurrentProcess( hwnd ))
2296 FIXME( "cannot set text %s of other process window %x\n", debugstr_a(lpString), hwnd );
2297 SetLastError( ERROR_ACCESS_DENIED );
2298 return FALSE;
2300 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2304 /*******************************************************************
2305 * SetWindowTextW (USER32.@)
2307 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2309 if (!WIN_IsCurrentProcess( hwnd ))
2311 FIXME( "cannot set text %s of other process window %x\n", debugstr_w(lpString), hwnd );
2312 SetLastError( ERROR_ACCESS_DENIED );
2313 return FALSE;
2315 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2319 /*******************************************************************
2320 * GetWindowTextLengthA (USER32.@)
2322 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2324 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2327 /*******************************************************************
2328 * GetWindowTextLengthW (USER32.@)
2330 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2332 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2336 /*******************************************************************
2337 * IsWindow (USER32.@)
2339 BOOL WINAPI IsWindow( HWND hwnd )
2341 WND *ptr;
2342 BOOL ret;
2344 if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2346 if (ptr != WND_OTHER_PROCESS)
2348 WIN_ReleasePtr( ptr );
2349 return TRUE;
2352 /* check other processes */
2353 SERVER_START_REQ( get_window_info )
2355 req->handle = hwnd;
2356 ret = !wine_server_call_err( req );
2358 SERVER_END_REQ;
2359 return ret;
2363 /***********************************************************************
2364 * GetWindowThreadProcessId (USER32.@)
2366 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2368 WND *ptr;
2369 DWORD tid = 0;
2371 if (!(ptr = WIN_GetPtr( hwnd )))
2373 SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2374 return 0;
2377 if (ptr != WND_OTHER_PROCESS)
2379 /* got a valid window */
2380 tid = ptr->tid;
2381 if (process) *process = GetCurrentProcessId();
2382 WIN_ReleasePtr( ptr );
2383 return tid;
2386 /* check other processes */
2387 SERVER_START_REQ( get_window_info )
2389 req->handle = hwnd;
2390 if (!wine_server_call_err( req ))
2392 tid = (DWORD)reply->tid;
2393 if (process) *process = (DWORD)reply->pid;
2396 SERVER_END_REQ;
2397 return tid;
2401 /*****************************************************************
2402 * GetParent (USER32.@)
2404 HWND WINAPI GetParent( HWND hwnd )
2406 WND *wndPtr;
2407 HWND retvalue = 0;
2409 if (!(wndPtr = WIN_GetPtr( hwnd )))
2411 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2412 return 0;
2414 if (wndPtr == WND_OTHER_PROCESS)
2416 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2417 if (style & (WS_POPUP | WS_CHILD))
2419 SERVER_START_REQ( get_window_tree )
2421 req->handle = hwnd;
2422 if (!wine_server_call_err( req ))
2424 if (style & WS_CHILD) retvalue = reply->parent;
2425 else retvalue = reply->owner;
2428 SERVER_END_REQ;
2431 else
2433 if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2434 else if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2435 WIN_ReleasePtr( wndPtr );
2437 return retvalue;
2441 /*****************************************************************
2442 * GetAncestor (USER32.@)
2444 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2446 WND *win;
2447 HWND *list, ret = 0;
2449 if (type == GA_PARENT)
2451 if (!(win = WIN_GetPtr( hwnd )))
2453 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2454 return 0;
2456 if (win != WND_OTHER_PROCESS)
2458 ret = win->parent;
2459 WIN_ReleasePtr( win );
2461 else /* need to query the server */
2463 SERVER_START_REQ( get_window_tree )
2465 req->handle = hwnd;
2466 if (!wine_server_call_err( req )) ret = reply->parent;
2468 SERVER_END_REQ;
2470 return ret;
2473 if (!(list = WIN_ListParents( hwnd ))) return 0;
2475 if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd ); /* top-level window */
2476 else
2478 int count = 2;
2479 while (list[count]) count++;
2480 ret = list[count - 2]; /* get the one before the desktop */
2482 HeapFree( GetProcessHeap(), 0, list );
2484 if (ret && type == GA_ROOTOWNER)
2486 for (;;)
2488 HWND owner = GetWindow( ret, GW_OWNER );
2489 if (!owner) break;
2490 ret = owner;
2493 return ret;
2497 /*****************************************************************
2498 * SetParent (USER32.@)
2500 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2502 WND *wndPtr;
2503 HWND retvalue, full_handle;
2504 BOOL was_visible;
2506 if (!parent) parent = GetDesktopWindow();
2507 else parent = WIN_GetFullHandle( parent );
2509 if (!IsWindow( parent ))
2511 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2512 return 0;
2515 if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2516 return SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2518 hwnd = full_handle;
2520 if (USER_Driver.pSetParent)
2521 return USER_Driver.pSetParent( hwnd, parent );
2523 /* Windows hides the window first, then shows it again
2524 * including the WM_SHOWWINDOW messages and all */
2525 was_visible = ShowWindow( hwnd, SW_HIDE );
2527 if (!IsWindow( parent )) return 0;
2528 if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2530 retvalue = wndPtr->parent; /* old parent */
2531 if (parent != retvalue)
2533 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2535 if (parent != GetDesktopWindow()) /* a child window */
2537 if (!(wndPtr->dwStyle & WS_CHILD))
2539 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2540 if (menu) DestroyMenu( menu );
2544 WIN_ReleasePtr( wndPtr );
2546 /* SetParent additionally needs to make hwnd the topmost window
2547 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2548 WM_WINDOWPOSCHANGED notification messages.
2550 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2551 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2552 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2553 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2554 return retvalue;
2558 /*******************************************************************
2559 * IsChild (USER32.@)
2561 BOOL WINAPI IsChild( HWND parent, HWND child )
2563 HWND *list = WIN_ListParents( child );
2564 int i;
2565 BOOL ret;
2567 if (!list) return FALSE;
2568 parent = WIN_GetFullHandle( parent );
2569 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2570 ret = (list[i] != 0);
2571 HeapFree( GetProcessHeap(), 0, list );
2572 return ret;
2576 /***********************************************************************
2577 * IsWindowVisible (USER32.@)
2579 BOOL WINAPI IsWindowVisible( HWND hwnd )
2581 HWND *list;
2582 BOOL retval;
2583 int i;
2585 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2586 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2587 for (i = 0; list[i]; i++)
2588 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2589 retval = !list[i];
2590 HeapFree( GetProcessHeap(), 0, list );
2591 return retval;
2595 /***********************************************************************
2596 * WIN_IsWindowDrawable
2598 * hwnd is drawable when it is visible, all parents are not
2599 * minimized, and it is itself not minimized unless we are
2600 * trying to draw its default class icon.
2602 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2604 HWND *list;
2605 BOOL retval;
2606 int i;
2607 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2609 if (!(style & WS_VISIBLE)) return FALSE;
2610 if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON )) return FALSE;
2612 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2613 for (i = 0; list[i]; i++)
2614 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2615 break;
2616 retval = !list[i];
2617 HeapFree( GetProcessHeap(), 0, list );
2618 return retval;
2622 /*******************************************************************
2623 * GetTopWindow (USER32.@)
2625 HWND WINAPI GetTopWindow( HWND hwnd )
2627 if (!hwnd) hwnd = GetDesktopWindow();
2628 return GetWindow( hwnd, GW_CHILD );
2632 /*******************************************************************
2633 * GetWindow (USER32.@)
2635 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2637 HWND retval = 0;
2639 if (rel == GW_OWNER) /* this one may be available locally */
2641 WND *wndPtr = WIN_GetPtr( hwnd );
2642 if (!wndPtr)
2644 SetLastError( ERROR_INVALID_HANDLE );
2645 return 0;
2647 if (wndPtr != WND_OTHER_PROCESS)
2649 retval = wndPtr->owner;
2650 WIN_ReleasePtr( wndPtr );
2651 return retval;
2653 /* else fall through to server call */
2656 SERVER_START_REQ( get_window_tree )
2658 req->handle = hwnd;
2659 if (!wine_server_call_err( req ))
2661 switch(rel)
2663 case GW_HWNDFIRST:
2664 retval = reply->first_sibling;
2665 break;
2666 case GW_HWNDLAST:
2667 retval = reply->last_sibling;
2668 break;
2669 case GW_HWNDNEXT:
2670 retval = reply->next_sibling;
2671 break;
2672 case GW_HWNDPREV:
2673 retval = reply->prev_sibling;
2674 break;
2675 case GW_OWNER:
2676 retval = reply->owner;
2677 break;
2678 case GW_CHILD:
2679 retval = reply->first_child;
2680 break;
2684 SERVER_END_REQ;
2685 return retval;
2689 /***********************************************************************
2690 * WIN_InternalShowOwnedPopups
2692 * Internal version of ShowOwnedPopups; Wine functions should use this
2693 * to avoid interfering with application calls to ShowOwnedPopups
2694 * and to make sure the application can't prevent showing/hiding.
2696 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2700 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2702 int count = 0;
2703 WND *pWnd;
2704 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2706 if (!win_array) return TRUE;
2709 * Show windows Lowest first, Highest last to preserve Z-Order
2711 while (win_array[count]) count++;
2712 while (--count >= 0)
2714 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2715 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2717 if (pWnd->dwStyle & WS_POPUP)
2719 if (fShow)
2721 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2722 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2725 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2727 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2728 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2731 else
2733 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2734 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2735 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2738 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2740 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2741 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2742 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2746 WIN_ReleaseWndPtr( pWnd );
2748 HeapFree( GetProcessHeap(), 0, win_array );
2750 return TRUE;
2753 /*******************************************************************
2754 * ShowOwnedPopups (USER32.@)
2756 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2758 int count = 0;
2759 WND *pWnd;
2760 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2762 if (!win_array) return TRUE;
2764 while (win_array[count]) count++;
2765 while (--count >= 0)
2767 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2768 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2770 if (pWnd->dwStyle & WS_POPUP)
2772 if (fShow)
2774 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2776 /* In Windows, ShowOwnedPopups(TRUE) generates
2777 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2778 * regardless of the state of the owner
2780 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2781 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2784 else
2786 if (IsWindowVisible(pWnd->hwndSelf))
2788 /* In Windows, ShowOwnedPopups(FALSE) generates
2789 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2790 * regardless of the state of the owner
2792 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2793 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2797 WIN_ReleaseWndPtr( pWnd );
2799 HeapFree( GetProcessHeap(), 0, win_array );
2800 return TRUE;
2804 /*******************************************************************
2805 * GetLastActivePopup (USER32.@)
2807 HWND WINAPI GetLastActivePopup( HWND hwnd )
2809 HWND retval;
2810 WND *wndPtr =WIN_FindWndPtr(hwnd);
2811 if (!wndPtr) return hwnd;
2812 retval = wndPtr->hwndLastActive;
2813 if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2814 WIN_ReleaseWndPtr(wndPtr);
2815 return retval;
2819 /*******************************************************************
2820 * WIN_ListParents
2822 * Build an array of all parents of a given window, starting with
2823 * the immediate parent. The array must be freed with HeapFree.
2824 * Returns NULL if window is a top-level window.
2826 HWND *WIN_ListParents( HWND hwnd )
2828 WND *win;
2829 HWND current, *list;
2830 int pos = 0, size = 16, count = 0;
2832 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2834 current = hwnd;
2835 for (;;)
2837 if (!(win = WIN_GetPtr( current ))) goto empty;
2838 if (win == WND_OTHER_PROCESS) break; /* need to do it the hard way */
2839 list[pos] = win->parent;
2840 WIN_ReleasePtr( win );
2841 if (!(current = list[pos]))
2843 if (!pos) goto empty;
2844 return list;
2846 if (++pos == size - 1)
2848 /* need to grow the list */
2849 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2850 if (!new_list) goto empty;
2851 list = new_list;
2852 size += 16;
2856 /* at least one parent belongs to another process, have to query the server */
2858 for (;;)
2860 count = 0;
2861 SERVER_START_REQ( get_window_parents )
2863 req->handle = hwnd;
2864 wine_server_set_reply( req, list, (size-1) * sizeof(HWND) );
2865 if (!wine_server_call( req )) count = reply->count;
2867 SERVER_END_REQ;
2868 if (!count) goto empty;
2869 if (size > count)
2871 list[count] = 0;
2872 return list;
2874 HeapFree( GetProcessHeap(), 0, list );
2875 size = count + 1;
2876 if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2879 empty:
2880 HeapFree( GetProcessHeap(), 0, list );
2881 return NULL;
2885 /*******************************************************************
2886 * WIN_ListChildren
2888 * Build an array of the children of a given window. The array must be
2889 * freed with HeapFree. Returns NULL when no windows are found.
2891 HWND *WIN_ListChildren( HWND hwnd )
2893 return list_window_children( hwnd, 0, 0 );
2897 /*******************************************************************
2898 * EnumWindows (USER32.@)
2900 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2902 HWND *list;
2903 BOOL ret = TRUE;
2904 int i, iWndsLocks;
2906 /* We have to build a list of all windows first, to avoid */
2907 /* unpleasant side-effects, for instance if the callback */
2908 /* function changes the Z-order of the windows. */
2910 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2912 /* Now call the callback function for every window */
2914 iWndsLocks = WIN_SuspendWndsLock();
2915 for (i = 0; list[i]; i++)
2917 /* Make sure that the window still exists */
2918 if (!IsWindow( list[i] )) continue;
2919 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2921 WIN_RestoreWndsLock(iWndsLocks);
2922 HeapFree( GetProcessHeap(), 0, list );
2923 return ret;
2927 /**********************************************************************
2928 * EnumThreadWindows (USER32.@)
2930 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2932 HWND *list;
2933 int i, iWndsLocks;
2935 if (!(list = list_window_children( GetDesktopWindow(), 0, GetCurrentThreadId() )))
2936 return TRUE ;
2938 /* Now call the callback function for every window */
2940 iWndsLocks = WIN_SuspendWndsLock();
2941 for (i = 0; list[i]; i++)
2942 if (!func( list[i], lParam )) break;
2943 WIN_RestoreWndsLock(iWndsLocks);
2944 HeapFree( GetProcessHeap(), 0, list );
2945 return TRUE;
2949 /**********************************************************************
2950 * WIN_EnumChildWindows
2952 * Helper function for EnumChildWindows().
2954 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2956 HWND *childList;
2957 BOOL ret = FALSE;
2959 for ( ; *list; list++)
2961 /* Make sure that the window still exists */
2962 if (!IsWindow( *list )) continue;
2963 /* skip owned windows */
2964 if (GetWindow( *list, GW_OWNER )) continue;
2965 /* Build children list first */
2966 childList = WIN_ListChildren( *list );
2968 ret = func( *list, lParam );
2970 if (childList)
2972 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2973 HeapFree( GetProcessHeap(), 0, childList );
2975 if (!ret) return FALSE;
2977 return TRUE;
2981 /**********************************************************************
2982 * EnumChildWindows (USER32.@)
2984 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2986 HWND *list;
2987 int iWndsLocks;
2989 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2990 iWndsLocks = WIN_SuspendWndsLock();
2991 WIN_EnumChildWindows( list, func, lParam );
2992 WIN_RestoreWndsLock(iWndsLocks);
2993 HeapFree( GetProcessHeap(), 0, list );
2994 return TRUE;
2998 /*******************************************************************
2999 * AnyPopup (USER.52)
3001 BOOL16 WINAPI AnyPopup16(void)
3003 return AnyPopup();
3007 /*******************************************************************
3008 * AnyPopup (USER32.@)
3010 BOOL WINAPI AnyPopup(void)
3012 int i;
3013 BOOL retvalue;
3014 HWND *list = WIN_ListChildren( GetDesktopWindow() );
3016 if (!list) return FALSE;
3017 for (i = 0; list[i]; i++)
3019 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3021 retvalue = (list[i] != 0);
3022 HeapFree( GetProcessHeap(), 0, list );
3023 return retvalue;
3027 /*******************************************************************
3028 * FlashWindow (USER32.@)
3030 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3032 WND *wndPtr = WIN_FindWndPtr(hWnd);
3034 TRACE("%04x\n", hWnd);
3036 if (!wndPtr) return FALSE;
3037 hWnd = wndPtr->hwndSelf; /* make it a full handle */
3039 if (wndPtr->dwStyle & WS_MINIMIZE)
3041 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3043 HDC hDC = GetDC(hWnd);
3045 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
3046 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3048 ReleaseDC( hWnd, hDC );
3049 wndPtr->flags |= WIN_NCACTIVATED;
3051 else
3053 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3054 wndPtr->flags &= ~WIN_NCACTIVATED;
3056 WIN_ReleaseWndPtr(wndPtr);
3057 return TRUE;
3059 else
3061 WPARAM16 wparam;
3062 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3063 else wparam = (hWnd == GetActiveWindow());
3065 WIN_ReleaseWndPtr(wndPtr);
3066 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3067 return wparam;
3072 /*******************************************************************
3073 * GetWindowContextHelpId (USER32.@)
3075 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3077 DWORD retval;
3078 WND *wnd = WIN_FindWndPtr( hwnd );
3079 if (!wnd) return 0;
3080 retval = wnd->helpContext;
3081 WIN_ReleaseWndPtr(wnd);
3082 return retval;
3086 /*******************************************************************
3087 * SetWindowContextHelpId (USER32.@)
3089 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3091 WND *wnd = WIN_FindWndPtr( hwnd );
3092 if (!wnd) return FALSE;
3093 wnd->helpContext = id;
3094 WIN_ReleaseWndPtr(wnd);
3095 return TRUE;
3099 /*******************************************************************
3100 * DRAG_QueryUpdate
3102 * recursively find a child that contains spDragInfo->pt point
3103 * and send WM_QUERYDROPOBJECT
3105 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
3107 BOOL16 wParam, bResult = 0;
3108 POINT pt;
3109 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3110 RECT tempRect;
3112 if (!ptrDragInfo) return FALSE;
3114 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3116 GetWindowRect(hQueryWnd,&tempRect);
3118 if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
3120 if (!IsIconic( hQueryWnd ))
3122 GetClientRect( hQueryWnd, &tempRect );
3123 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
3125 if (PtInRect( &tempRect, pt))
3127 int i;
3128 HWND *list = WIN_ListChildren( hQueryWnd );
3130 wParam = 0;
3132 if (list)
3134 for (i = 0; list[i]; i++)
3136 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
3138 GetWindowRect( list[i], &tempRect );
3139 if (PtInRect( &tempRect, pt )) break;
3142 if (list[i])
3144 if (IsWindowEnabled( list[i] ))
3145 bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
3147 HeapFree( GetProcessHeap(), 0, list );
3149 if(bResult) return bResult;
3151 else wParam = 1;
3153 else wParam = 1;
3155 ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
3157 ptrDragInfo->hScope = hQueryWnd;
3159 if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
3160 else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
3162 if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3164 return bResult;
3168 /*******************************************************************
3169 * DragDetect (USER32.@)
3171 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3173 MSG msg;
3174 RECT rect;
3176 rect.left = pt.x - wDragWidth;
3177 rect.right = pt.x + wDragWidth;
3179 rect.top = pt.y - wDragHeight;
3180 rect.bottom = pt.y + wDragHeight;
3182 SetCapture(hWnd);
3184 while(1)
3186 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3188 if( msg.message == WM_LBUTTONUP )
3190 ReleaseCapture();
3191 return 0;
3193 if( msg.message == WM_MOUSEMOVE )
3195 POINT tmp;
3196 tmp.x = LOWORD(msg.lParam);
3197 tmp.y = HIWORD(msg.lParam);
3198 if( !PtInRect( &rect, tmp ))
3200 ReleaseCapture();
3201 return 1;
3205 WaitMessage();
3207 return 0;
3210 /******************************************************************************
3211 * DragObject (USER.464)
3213 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3214 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3216 MSG msg;
3217 LPDRAGINFO16 lpDragInfo;
3218 SEGPTR spDragInfo;
3219 HCURSOR16 hDragCursor=0, hOldCursor=0, hBummer=0;
3220 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3221 HCURSOR16 hCurrentCursor = 0;
3222 HWND16 hCurrentWnd = 0;
3224 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3225 spDragInfo = K32WOWGlobalLock16(hDragInfo);
3227 if( !lpDragInfo || !spDragInfo ) return 0L;
3229 if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
3231 GlobalFree16(hDragInfo);
3232 return 0L;
3235 if(hCursor)
3237 if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
3239 GlobalFree16(hDragInfo);
3240 return 0L;
3243 if( hDragCursor == hCursor ) hDragCursor = 0;
3244 else hCursor = hDragCursor;
3246 hOldCursor = SetCursor(hDragCursor);
3249 lpDragInfo->hWnd = hWnd;
3250 lpDragInfo->hScope = 0;
3251 lpDragInfo->wFlags = wObj;
3252 lpDragInfo->hList = szList; /* near pointer! */
3253 lpDragInfo->hOfStruct = hOfStruct;
3254 lpDragInfo->l = 0L;
3256 SetCapture(hWnd);
3257 ShowCursor( TRUE );
3261 GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
3263 *(lpDragInfo+1) = *lpDragInfo;
3265 lpDragInfo->pt.x = msg.pt.x;
3266 lpDragInfo->pt.y = msg.pt.y;
3268 /* update DRAGINFO struct */
3269 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3271 if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
3272 hCurrentCursor = hCursor;
3273 else
3275 hCurrentCursor = hBummer;
3276 lpDragInfo->hScope = 0;
3278 if( hCurrentCursor )
3279 SetCursor(hCurrentCursor);
3281 /* send WM_DRAGLOOP */
3282 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3283 (LPARAM) spDragInfo );
3284 /* send WM_DRAGSELECT or WM_DRAGMOVE */
3285 if( hCurrentWnd != lpDragInfo->hScope )
3287 if( hCurrentWnd )
3288 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3289 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3290 HIWORD(spDragInfo)) );
3291 hCurrentWnd = lpDragInfo->hScope;
3292 if( hCurrentWnd )
3293 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3295 else
3296 if( hCurrentWnd )
3297 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3299 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3301 ReleaseCapture();
3302 ShowCursor( FALSE );
3304 if( hCursor )
3306 SetCursor( hOldCursor );
3307 if (hDragCursor) DestroyCursor( hDragCursor );
3310 if( hCurrentCursor != hBummer )
3311 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3312 (WPARAM16)hWnd, (LPARAM)spDragInfo );
3313 else
3314 msg.lParam = 0;
3315 GlobalFree16(hDragInfo);
3317 return (DWORD)(msg.lParam);
3321 /******************************************************************************
3322 * GetWindowModuleFileNameA (USER32.@)
3324 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3326 FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3327 hwnd, lpszFileName, cchFileNameMax);
3328 return 0;
3331 /******************************************************************************
3332 * GetWindowModuleFileNameW (USER32.@)
3334 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3336 FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3337 hwnd, lpszFileName, cchFileNameMax);
3338 return 0;