Silence the pthread_kill_other_threads_np FIXME.
[wine/multimedia.git] / windows / win.c
blobe0c5e31bf766df9a9a1e133322daf91eaabea5c5
1 /*
2 * Window related functions
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "windef.h"
11 #include "wine/winbase16.h"
12 #include "wine/winuser16.h"
13 #include "wine/server.h"
14 #include "wine/unicode.h"
15 #include "win.h"
16 #include "heap.h"
17 #include "user.h"
18 #include "dce.h"
19 #include "controls.h"
20 #include "cursoricon.h"
21 #include "hook.h"
22 #include "message.h"
23 #include "queue.h"
24 #include "task.h"
25 #include "winpos.h"
26 #include "winerror.h"
27 #include "stackframe.h"
28 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(win);
31 DECLARE_DEBUG_CHANNEL(msg);
33 #define BAD_WND_PTR ((WND *)1) /* returned by get_wnd_ptr on bad window handles */
34 #define NB_USER_HANDLES (LAST_USER_HANDLE - FIRST_USER_HANDLE + 1)
36 /**********************************************************************/
38 /* Desktop window */
39 static WND *pWndDesktop = NULL;
41 static WORD wDragWidth = 4;
42 static WORD wDragHeight= 3;
44 static void *user_handles[NB_USER_HANDLES];
46 /* thread safeness */
47 extern SYSLEVEL USER_SysLevel; /* FIXME */
49 /***********************************************************************
50 * WIN_SuspendWndsLock
52 * Suspend the lock on WND structures.
53 * Returns the number of locks suspended
55 int WIN_SuspendWndsLock( void )
57 int isuspendedLocks = _ConfirmSysLevel( &USER_SysLevel );
58 int count = isuspendedLocks;
60 while ( count-- > 0 )
61 _LeaveSysLevel( &USER_SysLevel );
63 return isuspendedLocks;
66 /***********************************************************************
67 * WIN_RestoreWndsLock
69 * Restore the suspended locks on WND structures
71 void WIN_RestoreWndsLock( int ipreviousLocks )
73 while ( ipreviousLocks-- > 0 )
74 _EnterSysLevel( &USER_SysLevel );
77 /***********************************************************************
78 * create_window_handle
80 * Create a window handle with the server.
82 static WND *create_window_handle( HWND parent, HWND owner, INT size )
84 BOOL res;
85 user_handle_t handle = 0;
86 WORD index;
87 WND *win = HeapAlloc( GetProcessHeap(), 0, size );
89 if (!win) return NULL;
91 USER_Lock();
93 SERVER_START_REQ( create_window )
95 req->parent = parent;
96 req->owner = owner;
97 if ((res = !SERVER_CALL_ERR())) handle = req->handle;
99 SERVER_END_REQ;
101 if (!res)
103 USER_Unlock();
104 HeapFree( GetProcessHeap(), 0, win );
105 return NULL;
107 index = LOWORD(handle) - FIRST_USER_HANDLE;
108 assert( index < NB_USER_HANDLES );
109 user_handles[index] = win;
110 win->hwndSelf = handle;
111 win->dwMagic = WND_MAGIC;
112 win->irefCount = 1;
113 return win;
117 /***********************************************************************
118 * free_window_handle
120 * Free a window handle.
122 static WND *free_window_handle( HWND hwnd )
124 WND *ptr;
125 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
127 if (index >= NB_USER_HANDLES) return NULL;
128 USER_Lock();
129 if ((ptr = user_handles[index]))
131 SERVER_START_REQ( destroy_window )
133 req->handle = hwnd;
134 if (!SERVER_CALL_ERR())
135 user_handles[index] = NULL;
136 else
137 ptr = NULL;
139 SERVER_END_REQ;
141 USER_Unlock();
142 if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
143 return ptr;
147 /***********************************************************************
148 * get_wnd_ptr
150 * Return a pointer to the WND structure if local to the process,
151 * or BAD_WND_PTR is handle is local but not valid.
152 * If ret value is a valid pointer, the user lock is held.
154 static WND *get_wnd_ptr( HWND hwnd )
156 WND * ptr;
157 WORD index = LOWORD(hwnd) - FIRST_USER_HANDLE;
159 if (index >= NB_USER_HANDLES) return BAD_WND_PTR;
161 USER_Lock();
162 if ((ptr = user_handles[index]))
164 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
165 return ptr;
166 ptr = BAD_WND_PTR;
168 USER_Unlock();
169 return ptr;
173 /***********************************************************************
174 * WIN_IsCurrentProcess
176 * Check whether a given window belongs to the current process.
178 BOOL WIN_IsCurrentProcess( HWND hwnd )
180 WND *ptr;
182 if (!(ptr = get_wnd_ptr( hwnd )) || ptr == BAD_WND_PTR) return FALSE;
183 USER_Unlock();
184 return TRUE;
188 /***********************************************************************
189 * WIN_IsCurrentThread
191 * Check whether a given window belongs to the current thread.
193 BOOL WIN_IsCurrentThread( HWND hwnd )
195 WND *ptr;
196 BOOL ret = FALSE;
198 if ((ptr = get_wnd_ptr( hwnd )) && ptr != BAD_WND_PTR)
200 ret = (ptr->tid == GetCurrentThreadId());
201 USER_Unlock();
203 return ret;
207 /***********************************************************************
208 * WIN_Handle32
210 * Convert a 16-bit window handle to a full 32-bit handle.
212 HWND WIN_Handle32( HWND16 hwnd16 )
214 WND *ptr;
215 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
217 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
218 /* do sign extension for -2 and -3 */
219 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
221 if ((ptr = get_wnd_ptr( hwnd )))
223 if (ptr != BAD_WND_PTR)
225 hwnd = ptr->hwndSelf;
226 USER_Unlock();
229 else /* may belong to another process */
231 SERVER_START_REQ( get_window_info )
233 req->handle = hwnd;
234 if (!SERVER_CALL_ERR()) hwnd = req->full_handle;
236 SERVER_END_REQ;
238 return hwnd;
242 /***********************************************************************
243 * WIN_FindWndPtr
245 * Return a pointer to the WND structure corresponding to a HWND.
247 WND * WIN_FindWndPtr( HWND hwnd )
249 WND * ptr;
251 if (!hwnd) return NULL;
253 if ((ptr = get_wnd_ptr( hwnd )))
255 if (ptr != BAD_WND_PTR)
257 /* increment destruction monitoring */
258 ptr->irefCount++;
259 return ptr;
262 else if (IsWindow( hwnd )) /* check other processes */
264 ERR( "window %04x belongs to other process\n", hwnd );
265 /* DbgBreakPoint(); */
267 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
268 return NULL;
272 /***********************************************************************
273 * WIN_LockWndPtr
275 * Use in case the wnd ptr is not initialized with WIN_FindWndPtr
276 * but by initWndPtr;
277 * Returns the locked initialisation pointer
279 WND *WIN_LockWndPtr(WND *initWndPtr)
281 if(!initWndPtr) return 0;
283 /* Lock all WND structures for thread safeness*/
284 USER_Lock();
285 /*and increment destruction monitoring*/
286 initWndPtr->irefCount++;
288 return initWndPtr;
292 /***********************************************************************
293 * WIN_ReleaseWndPtr
295 * Release the pointer to the WND structure.
297 void WIN_ReleaseWndPtr(WND *wndPtr)
299 if(!wndPtr) return;
301 /*Decrement destruction monitoring value*/
302 wndPtr->irefCount--;
303 /* Check if it's time to release the memory*/
304 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
306 /* Release memory */
307 free_window_handle( wndPtr->hwndSelf );
309 else if(wndPtr->irefCount < 0)
311 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
312 ERR("forgot a Lock on %p somewhere\n",wndPtr);
314 /*unlock all WND structures for thread safeness*/
315 USER_Unlock();
318 /***********************************************************************
319 * WIN_UpdateWndPtr
321 * Updates the value of oldPtr to newPtr.
323 void WIN_UpdateWndPtr(WND **oldPtr, WND *newPtr)
325 WND *tmpWnd = NULL;
327 tmpWnd = WIN_LockWndPtr(newPtr);
328 WIN_ReleaseWndPtr(*oldPtr);
329 *oldPtr = tmpWnd;
334 /***********************************************************************
335 * WIN_UnlinkWindow
337 * Remove a window from the siblings linked list.
339 void WIN_UnlinkWindow( HWND hwnd )
341 WIN_LinkWindow( hwnd, 0, 0 );
345 /***********************************************************************
346 * WIN_LinkWindow
348 * Insert a window into the siblings linked list.
349 * The window is inserted after the specified window, which can also
350 * be specified as HWND_TOP or HWND_BOTTOM.
351 * If parent is 0, window is unlinked from the tree.
353 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
355 WND *wndPtr, **ppWnd, *parentPtr = NULL;
356 BOOL ret;
358 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return;
359 if (parent && !(parentPtr = WIN_FindWndPtr( parent )))
361 WIN_ReleaseWndPtr(wndPtr);
362 return;
365 SERVER_START_REQ( link_window )
367 req->handle = hwnd;
368 req->parent = parent;
369 req->previous = hwndInsertAfter;
370 ret = !SERVER_CALL_ERR();
372 SERVER_END_REQ;
373 if (!ret) goto done;
375 /* first unlink it if it is linked */
376 if (wndPtr->parent)
378 ppWnd = &wndPtr->parent->child;
379 while (*ppWnd && *ppWnd != wndPtr) ppWnd = &(*ppWnd)->next;
380 if (*ppWnd) *ppWnd = wndPtr->next;
383 if (parentPtr)
385 wndPtr->parent = parentPtr;
386 if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM))
388 ppWnd = &parentPtr->child; /* Point to first sibling hwnd */
389 if (hwndInsertAfter == HWND_BOTTOM) /* Find last sibling hwnd */
390 while (*ppWnd) ppWnd = &(*ppWnd)->next;
392 else /* Normal case */
394 WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter );
395 if (!afterPtr) goto done;
396 ppWnd = &afterPtr->next;
397 WIN_ReleaseWndPtr(afterPtr);
399 wndPtr->next = *ppWnd;
400 *ppWnd = wndPtr;
402 else wndPtr->next = NULL; /* unlinked */
404 done:
405 WIN_ReleaseWndPtr( parentPtr );
406 WIN_ReleaseWndPtr( wndPtr );
410 /***********************************************************************
411 * WIN_FindWinToRepaint
413 * Find a window that needs repaint.
415 HWND WIN_FindWinToRepaint( HWND hwnd )
417 HWND hwndRet;
418 WND *pWnd;
420 /* Note: the desktop window never gets WM_PAINT messages
421 * The real reason why is because Windows DesktopWndProc
422 * does ValidateRgn inside WM_ERASEBKGND handler.
424 if (hwnd == GetDesktopWindow()) hwnd = 0;
426 pWnd = hwnd ? WIN_FindWndPtr(hwnd) : WIN_LockWndPtr(pWndDesktop->child);
428 for ( ; pWnd ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
430 if (!(pWnd->dwStyle & WS_VISIBLE)) continue;
431 if ((pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT)) &&
432 WIN_IsCurrentThread( pWnd->hwndSelf ))
433 break;
434 if (pWnd->child )
436 if ((hwndRet = WIN_FindWinToRepaint( pWnd->child->hwndSelf )) )
438 WIN_ReleaseWndPtr(pWnd);
439 return hwndRet;
444 if(!pWnd)
446 TRACE("nothing found\n");
447 return 0;
449 hwndRet = pWnd->hwndSelf;
451 /* look among siblings if we got a transparent window */
452 while (pWnd)
454 if (!(pWnd->dwExStyle & WS_EX_TRANSPARENT) &&
455 (pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT)) &&
456 WIN_IsCurrentThread( pWnd->hwndSelf ))
458 hwndRet = pWnd->hwndSelf;
459 WIN_ReleaseWndPtr(pWnd);
460 break;
462 WIN_UpdateWndPtr(&pWnd,pWnd->next);
464 TRACE("found %04x\n",hwndRet);
465 return hwndRet;
469 /***********************************************************************
470 * WIN_DestroyWindow
472 * Destroy storage associated to a window. "Internals" p.358
473 * returns a locked wndPtr->next
475 static WND* WIN_DestroyWindow( WND* wndPtr )
477 HWND hwnd = wndPtr->hwndSelf;
478 WND *pWnd;
480 TRACE("%04x\n", wndPtr->hwndSelf );
482 /* free child windows */
483 WIN_LockWndPtr(wndPtr->child);
484 while ((pWnd = wndPtr->child))
486 wndPtr->child = WIN_DestroyWindow( pWnd );
487 WIN_ReleaseWndPtr(pWnd);
491 * Clear the update region to make sure no WM_PAINT messages will be
492 * generated for this window while processing the WM_NCDESTROY.
494 RedrawWindow( wndPtr->hwndSelf, NULL, 0,
495 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
498 * Send the WM_NCDESTROY to the window being destroyed.
500 SendMessageA( wndPtr->hwndSelf, WM_NCDESTROY, 0, 0);
502 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
504 WINPOS_CheckInternalPos( hwnd );
505 if( hwnd == GetCapture()) ReleaseCapture();
507 /* free resources associated with the window */
509 TIMER_RemoveWindowTimers( wndPtr->hwndSelf );
510 PROPERTY_RemoveWindowProps( wndPtr );
512 /* toss stale messages from the queue */
514 QUEUE_CleanupWindow( hwnd );
515 wndPtr->hmemTaskQ = 0;
517 if (!(wndPtr->dwStyle & WS_CHILD))
518 if (wndPtr->wIDmenu)
520 DestroyMenu( wndPtr->wIDmenu );
521 wndPtr->wIDmenu = 0;
523 if (wndPtr->hSysMenu)
525 DestroyMenu( wndPtr->hSysMenu );
526 wndPtr->hSysMenu = 0;
528 USER_Driver.pDestroyWindow( wndPtr->hwndSelf );
529 DCE_FreeWindowDCE( wndPtr->hwndSelf ); /* Always do this to catch orphaned DCs */
530 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
531 CLASS_RemoveWindow( wndPtr->class );
532 wndPtr->class = NULL;
533 wndPtr->dwMagic = 0; /* Mark it as invalid */
535 WIN_UpdateWndPtr(&pWnd,wndPtr->next);
537 return pWnd;
540 /***********************************************************************
541 * WIN_DestroyThreadWindows
543 * Destroy all children of 'wnd' owned by the current thread.
544 * Return TRUE if something was done.
546 void WIN_DestroyThreadWindows( HWND hwnd )
548 HWND *list;
549 int i;
551 if (!(list = WIN_ListChildren( hwnd ))) return;
552 for (i = 0; list[i]; i++)
554 if (!IsWindow( list[i] )) continue;
555 if (WIN_IsCurrentThread( list[i] ))
556 DestroyWindow( list[i] );
557 else
558 WIN_DestroyThreadWindows( list[i] );
560 HeapFree( GetProcessHeap(), 0, list );
563 /***********************************************************************
564 * WIN_CreateDesktopWindow
566 * Create the desktop window.
568 BOOL WIN_CreateDesktopWindow(void)
570 struct tagCLASS *class;
571 HWND hwndDesktop;
572 INT wndExtra;
573 DWORD clsStyle;
574 WNDPROC winproc;
575 DCE *dce;
576 CREATESTRUCTA cs;
578 TRACE("Creating desktop window\n");
581 if (!WINPOS_CreateInternalPosAtom() ||
582 !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
583 &wndExtra, &winproc, &clsStyle, &dce )))
584 return FALSE;
586 pWndDesktop = create_window_handle( 0, 0, sizeof(WND) + wndExtra );
587 if (!pWndDesktop) return FALSE;
588 hwndDesktop = pWndDesktop->hwndSelf;
590 pWndDesktop->tid = 0; /* nobody owns the desktop */
591 pWndDesktop->next = NULL;
592 pWndDesktop->child = NULL;
593 pWndDesktop->parent = NULL;
594 pWndDesktop->owner = 0;
595 pWndDesktop->class = class;
596 pWndDesktop->hInstance = 0;
597 pWndDesktop->rectWindow.left = 0;
598 pWndDesktop->rectWindow.top = 0;
599 pWndDesktop->rectWindow.right = GetSystemMetrics(SM_CXSCREEN);
600 pWndDesktop->rectWindow.bottom = GetSystemMetrics(SM_CYSCREEN);
601 pWndDesktop->rectClient = pWndDesktop->rectWindow;
602 pWndDesktop->text = NULL;
603 pWndDesktop->hmemTaskQ = 0;
604 pWndDesktop->hrgnUpdate = 0;
605 pWndDesktop->hwndLastActive = hwndDesktop;
606 pWndDesktop->dwStyle = WS_VISIBLE | WS_CLIPCHILDREN |
607 WS_CLIPSIBLINGS;
608 pWndDesktop->dwExStyle = 0;
609 pWndDesktop->clsStyle = clsStyle;
610 pWndDesktop->dce = NULL;
611 pWndDesktop->pVScroll = NULL;
612 pWndDesktop->pHScroll = NULL;
613 pWndDesktop->pProp = NULL;
614 pWndDesktop->wIDmenu = 0;
615 pWndDesktop->helpContext = 0;
616 pWndDesktop->flags = 0;
617 pWndDesktop->hSysMenu = 0;
618 pWndDesktop->userdata = 0;
619 pWndDesktop->winproc = winproc;
620 pWndDesktop->cbWndExtra = wndExtra;
622 cs.lpCreateParams = NULL;
623 cs.hInstance = 0;
624 cs.hMenu = 0;
625 cs.hwndParent = 0;
626 cs.x = 0;
627 cs.y = 0;
628 cs.cx = pWndDesktop->rectWindow.right;
629 cs.cy = pWndDesktop->rectWindow.bottom;
630 cs.style = pWndDesktop->dwStyle;
631 cs.dwExStyle = pWndDesktop->dwExStyle;
632 cs.lpszName = NULL;
633 cs.lpszClass = DESKTOP_CLASS_ATOM;
635 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE )) return FALSE;
637 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
638 WIN_ReleaseWndPtr( pWndDesktop );
639 return TRUE;
643 /***********************************************************************
644 * WIN_FixCoordinates
646 * Fix the coordinates - Helper for WIN_CreateWindowEx.
647 * returns default show mode in sw.
648 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
650 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
652 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
653 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
655 if (cs->style & (WS_CHILD | WS_POPUP))
657 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
658 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
660 else /* overlapped window */
662 STARTUPINFOA info;
664 GetStartupInfoA( &info );
666 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
668 /* Never believe Microsoft's documentation... CreateWindowEx doc says
669 * that if an overlapped window is created with WS_VISIBLE style bit
670 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
671 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
672 * reveals that
674 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
675 * 2) it does not ignore the y parameter as the docs claim; instead, it
676 * uses it as second parameter to ShowWindow() unless y is either
677 * CW_USEDEFAULT or CW_USEDEFAULT16.
679 * The fact that we didn't do 2) caused bogus windows pop up when wine
680 * was running apps that were using this obscure feature. Example -
681 * calc.exe that comes with Win98 (only Win98, it's different from
682 * the one that comes with Win95 and NT)
684 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
685 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
686 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
689 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
691 if (info.dwFlags & STARTF_USESIZE)
693 cs->cx = info.dwXSize;
694 cs->cy = info.dwYSize;
696 else /* if no other hint from the app, pick 3/4 of the screen real estate */
698 RECT r;
699 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
700 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
701 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
708 /***********************************************************************
709 * WIN_CreateWindowEx
711 * Implementation of CreateWindowEx().
713 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
714 WINDOWPROCTYPE type )
716 INT sw = SW_SHOW;
717 struct tagCLASS *classPtr;
718 WND *wndPtr;
719 HWND hwnd, hwndLinkAfter, parent, owner;
720 POINT maxSize, maxPos, minTrack, maxTrack;
721 INT wndExtra;
722 DWORD clsStyle;
723 WNDPROC winproc;
724 DCE *dce;
725 BOOL unicode = (type == WIN_PROC_32W);
727 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%04x menu=%04x inst=%08x params=%p\n",
728 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszName) : debugres_a(cs->lpszName),
729 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszClass) : debugres_a(cs->lpszClass),
730 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
731 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
733 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
734 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
736 /* Find the parent window */
738 parent = GetDesktopWindow();
739 owner = 0;
740 if (cs->hwndParent)
742 /* Make sure parent is valid */
743 if (!IsWindow( cs->hwndParent ))
745 WARN("Bad parent %04x\n", cs->hwndParent );
746 return 0;
748 if (cs->style & WS_CHILD) parent = cs->hwndParent;
749 else owner = GetAncestor( cs->hwndParent, GA_ROOT );
751 else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP))
753 WARN("No parent for child window\n" );
754 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
757 /* Find the window class */
758 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
759 &wndExtra, &winproc, &clsStyle, &dce )))
761 WARN("Bad class '%s'\n", cs->lpszClass );
762 return 0;
765 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
767 /* Correct the window style - stage 1
769 * These are patches that appear to affect both the style loaded into the
770 * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
772 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
773 * why does the user get to set it?
776 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
777 * tested for WS_POPUP
779 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
780 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
781 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
782 cs->dwExStyle |= WS_EX_WINDOWEDGE;
783 else
784 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
786 /* Create the window structure */
788 if (!(wndPtr = create_window_handle( parent, owner,
789 sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
791 TRACE("out of memory\n" );
792 return 0;
794 hwnd = wndPtr->hwndSelf;
796 /* Fill the window structure */
798 wndPtr->tid = GetCurrentThreadId();
799 wndPtr->next = NULL;
800 wndPtr->child = NULL;
801 wndPtr->owner = owner;
802 wndPtr->parent = WIN_FindWndPtr( parent );
803 WIN_ReleaseWndPtr(wndPtr->parent);
805 wndPtr->class = classPtr;
806 wndPtr->winproc = winproc;
807 wndPtr->hInstance = cs->hInstance;
808 wndPtr->text = NULL;
809 wndPtr->hmemTaskQ = InitThreadInput16( 0, 0 );
810 wndPtr->hrgnUpdate = 0;
811 wndPtr->hrgnWnd = 0;
812 wndPtr->hwndLastActive = hwnd;
813 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
814 wndPtr->dwExStyle = cs->dwExStyle;
815 wndPtr->clsStyle = clsStyle;
816 wndPtr->wIDmenu = 0;
817 wndPtr->helpContext = 0;
818 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
819 wndPtr->pVScroll = NULL;
820 wndPtr->pHScroll = NULL;
821 wndPtr->pProp = NULL;
822 wndPtr->userdata = 0;
823 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU)
824 ? MENU_GetSysMenu( hwnd, 0 ) : 0;
825 wndPtr->cbWndExtra = wndExtra;
827 if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
829 /* Call the WH_CBT hook */
831 hwndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
832 ? HWND_BOTTOM : HWND_TOP;
834 if (HOOK_IsHooked( WH_CBT ))
836 CBT_CREATEWNDA cbtc;
837 LRESULT ret;
839 cbtc.lpcs = cs;
840 cbtc.hwndInsertAfter = hwndLinkAfter;
841 ret = (type == WIN_PROC_32W) ? HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND,
842 (WPARAM)hwnd, (LPARAM)&cbtc)
843 : HOOK_CallHooksA(WH_CBT, HCBT_CREATEWND,
844 (WPARAM)hwnd, (LPARAM)&cbtc);
845 if (ret)
847 TRACE("CBT-hook returned 0\n");
848 free_window_handle( hwnd );
849 CLASS_RemoveWindow( classPtr );
850 hwnd = 0;
851 goto end;
855 /* Correct the window style - stage 2 */
857 if (!(cs->style & WS_CHILD))
859 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
860 if (!(cs->style & WS_POPUP))
862 wndPtr->dwStyle |= WS_CAPTION;
863 wndPtr->flags |= WIN_NEED_SIZE;
867 /* Get class or window DC if needed */
869 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
870 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
871 else wndPtr->dce = NULL;
873 /* Initialize the dimensions before sending WM_GETMINMAXINFO */
875 wndPtr->rectWindow.left = cs->x;
876 wndPtr->rectWindow.top = cs->y;
877 wndPtr->rectWindow.right = cs->x + cs->cx;
878 wndPtr->rectWindow.bottom = cs->y + cs->cy;
879 wndPtr->rectClient = wndPtr->rectWindow;
881 /* Send the WM_GETMINMAXINFO message and fix the size if needed */
883 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
885 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
886 if (maxSize.x < cs->cx) cs->cx = maxSize.x;
887 if (maxSize.y < cs->cy) cs->cy = maxSize.y;
888 if (cs->cx < minTrack.x ) cs->cx = minTrack.x;
889 if (cs->cy < minTrack.y ) cs->cy = minTrack.y;
892 if (cs->cx < 0) cs->cx = 0;
893 if (cs->cy < 0) cs->cy = 0;
895 wndPtr->rectWindow.left = cs->x;
896 wndPtr->rectWindow.top = cs->y;
897 wndPtr->rectWindow.right = cs->x + cs->cx;
898 wndPtr->rectWindow.bottom = cs->y + cs->cy;
899 wndPtr->rectClient = wndPtr->rectWindow;
901 /* Set the window menu */
903 if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
905 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
906 else
908 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
909 if (menuName)
911 if (HIWORD(cs->hInstance))
912 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
913 else
914 cs->hMenu = LoadMenu16(cs->hInstance,menuName);
916 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
920 else wndPtr->wIDmenu = (UINT)cs->hMenu;
922 if (!USER_Driver.pCreateWindow( wndPtr->hwndSelf, cs, unicode))
924 WARN("aborted by WM_xxCREATE!\n");
925 WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr ));
926 CLASS_RemoveWindow( classPtr );
927 WIN_ReleaseWndPtr(wndPtr);
928 return 0;
931 if( (wndPtr->dwStyle & WS_CHILD) && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
933 /* Notify the parent window only */
935 SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
936 MAKEWPARAM(WM_CREATE, wndPtr->wIDmenu), (LPARAM)hwnd );
937 if( !IsWindow(hwnd) )
939 hwnd = 0;
940 goto end;
944 if (cs->style & WS_VISIBLE)
946 /* in case WS_VISIBLE got set in the meantime */
947 wndPtr->dwStyle &= ~WS_VISIBLE;
948 ShowWindow( hwnd, sw );
951 /* Call WH_SHELL hook */
953 if (!(wndPtr->dwStyle & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
954 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
956 TRACE("created window %04x\n", hwnd);
957 end:
958 WIN_ReleaseWndPtr(wndPtr);
959 return hwnd;
963 /***********************************************************************
964 * CreateWindow (USER.41)
966 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
967 DWORD style, INT16 x, INT16 y, INT16 width,
968 INT16 height, HWND16 parent, HMENU16 menu,
969 HINSTANCE16 instance, LPVOID data )
971 return CreateWindowEx16( 0, className, windowName, style,
972 x, y, width, height, parent, menu, instance, data );
976 /***********************************************************************
977 * CreateWindowEx (USER.452)
979 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
980 LPCSTR windowName, DWORD style, INT16 x,
981 INT16 y, INT16 width, INT16 height,
982 HWND16 parent, HMENU16 menu,
983 HINSTANCE16 instance, LPVOID data )
985 ATOM classAtom;
986 CREATESTRUCTA cs;
987 char buffer[256];
989 /* Find the class atom */
991 if (HIWORD(className))
993 if (!(classAtom = GlobalFindAtomA( className )))
995 ERR( "bad class name %s\n", debugres_a(className) );
996 return 0;
999 else
1001 classAtom = LOWORD(className);
1002 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1004 ERR( "bad atom %x\n", classAtom);
1005 return 0;
1007 className = buffer;
1010 /* Fix the coordinates */
1012 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1013 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1014 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1015 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1017 /* Create the window */
1019 cs.lpCreateParams = data;
1020 cs.hInstance = (HINSTANCE)instance;
1021 cs.hMenu = (HMENU)menu;
1022 cs.hwndParent = WIN_Handle32( parent );
1023 cs.style = style;
1024 cs.lpszName = windowName;
1025 cs.lpszClass = className;
1026 cs.dwExStyle = exStyle;
1028 return WIN_Handle16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
1032 /***********************************************************************
1033 * CreateWindowExA (USER32.@)
1035 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1036 LPCSTR windowName, DWORD style, INT x,
1037 INT y, INT width, INT height,
1038 HWND parent, HMENU menu,
1039 HINSTANCE instance, LPVOID data )
1041 ATOM classAtom;
1042 CREATESTRUCTA cs;
1043 char buffer[256];
1045 if(!instance)
1046 instance=GetModuleHandleA(NULL);
1048 if(exStyle & WS_EX_MDICHILD)
1049 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1051 /* Find the class atom */
1053 if (HIWORD(className))
1055 if (!(classAtom = GlobalFindAtomA( className )))
1057 ERR( "bad class name %s\n", debugres_a(className) );
1058 return 0;
1061 else
1063 classAtom = LOWORD(className);
1064 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1066 ERR( "bad atom %x\n", classAtom);
1067 return 0;
1069 className = buffer;
1072 /* Create the window */
1074 cs.lpCreateParams = data;
1075 cs.hInstance = instance;
1076 cs.hMenu = menu;
1077 cs.hwndParent = parent;
1078 cs.x = x;
1079 cs.y = y;
1080 cs.cx = width;
1081 cs.cy = height;
1082 cs.style = style;
1083 cs.lpszName = windowName;
1084 cs.lpszClass = className;
1085 cs.dwExStyle = exStyle;
1087 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1091 /***********************************************************************
1092 * CreateWindowExW (USER32.@)
1094 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1095 LPCWSTR windowName, DWORD style, INT x,
1096 INT y, INT width, INT height,
1097 HWND parent, HMENU menu,
1098 HINSTANCE instance, LPVOID data )
1100 ATOM classAtom;
1101 CREATESTRUCTW cs;
1102 WCHAR buffer[256];
1104 if(!instance)
1105 instance=GetModuleHandleA(NULL);
1107 if(exStyle & WS_EX_MDICHILD)
1108 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1110 /* Find the class atom */
1112 if (HIWORD(className))
1114 if (!(classAtom = GlobalFindAtomW( className )))
1116 ERR( "bad class name %s\n", debugres_w(className) );
1117 return 0;
1120 else
1122 classAtom = LOWORD(className);
1123 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1125 ERR( "bad atom %x\n", classAtom);
1126 return 0;
1128 className = buffer;
1131 /* Create the window */
1133 cs.lpCreateParams = data;
1134 cs.hInstance = instance;
1135 cs.hMenu = menu;
1136 cs.hwndParent = parent;
1137 cs.x = x;
1138 cs.y = y;
1139 cs.cx = width;
1140 cs.cy = height;
1141 cs.style = style;
1142 cs.lpszName = windowName;
1143 cs.lpszClass = className;
1144 cs.dwExStyle = exStyle;
1146 /* Note: we rely on the fact that CREATESTRUCTA and */
1147 /* CREATESTRUCTW have the same layout. */
1148 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1152 /***********************************************************************
1153 * WIN_SendDestroyMsg
1155 static void WIN_SendDestroyMsg( HWND hwnd )
1157 if( CARET_GetHwnd() == hwnd) DestroyCaret();
1158 if (USER_Driver.pResetSelectionOwner)
1159 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1162 * Send the WM_DESTROY to the window.
1164 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1167 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1168 * make sure that the window still exists when we come back.
1170 if (IsWindow(hwnd))
1172 HWND* pWndArray;
1173 int i;
1175 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1177 /* start from the end (FIXME: is this needed?) */
1178 for (i = 0; pWndArray[i]; i++) ;
1180 while (--i >= 0)
1182 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1184 HeapFree( GetProcessHeap(), 0, pWndArray );
1186 else
1187 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1191 /***********************************************************************
1192 * DestroyWindow (USER32.@)
1194 BOOL WINAPI DestroyWindow( HWND hwnd )
1196 WND * wndPtr;
1197 BOOL retvalue;
1198 HWND h;
1200 hwnd = WIN_GetFullHandle( hwnd );
1201 TRACE("(%04x)\n", hwnd);
1203 /* Initialization */
1205 if (hwnd == GetDesktopWindow()) return FALSE; /* Can't destroy desktop */
1207 /* Look whether the focus is within the tree of windows we will
1208 * be destroying.
1210 h = GetFocus();
1211 if (h == hwnd || IsChild( hwnd, h ))
1213 HWND parent = GetAncestor( hwnd, GA_PARENT );
1214 if (parent == GetDesktopWindow()) parent = 0;
1215 SetFocus( parent );
1218 /* Call hooks */
1220 if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
1222 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1223 if (!(wndPtr->dwStyle & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1225 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
1226 /* FIXME: clean up palette - see "Internals" p.352 */
1229 if( !QUEUE_IsExitingQueue(wndPtr->hmemTaskQ) )
1230 if( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
1232 /* Notify the parent window only */
1233 SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
1234 MAKEWPARAM(WM_DESTROY, wndPtr->wIDmenu), (LPARAM)hwnd );
1235 if( !IsWindow(hwnd) )
1237 retvalue = TRUE;
1238 goto end;
1242 if (USER_Driver.pResetSelectionOwner)
1243 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1245 /* Hide the window */
1247 ShowWindow( hwnd, SW_HIDE );
1248 if (!IsWindow(hwnd))
1250 retvalue = TRUE;
1251 goto end;
1254 /* Recursively destroy owned windows */
1256 if( !(wndPtr->dwStyle & WS_CHILD) )
1258 HWND owner;
1260 for (;;)
1262 int i, got_one = 0;
1263 HWND *list = WIN_ListChildren( wndPtr->parent->hwndSelf );
1264 if (list)
1266 for (i = 0; list[i]; i++)
1268 WND *siblingPtr;
1269 if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1270 if (!(siblingPtr = WIN_FindWndPtr( list[i] ))) continue;
1271 if (siblingPtr->hmemTaskQ == wndPtr->hmemTaskQ)
1273 WIN_ReleaseWndPtr( siblingPtr );
1274 DestroyWindow( list[i] );
1275 got_one = 1;
1276 continue;
1278 else siblingPtr->owner = 0;
1279 WIN_ReleaseWndPtr( siblingPtr );
1281 HeapFree( GetProcessHeap(), 0, list );
1283 if (!got_one) break;
1286 WINPOS_ActivateOtherWindow( hwnd );
1288 if ((owner = GetWindow( hwnd, GW_OWNER )))
1290 WND *ptr = WIN_FindWndPtr( owner );
1291 if (ptr)
1293 if (ptr->hwndLastActive == hwnd) ptr->hwndLastActive = owner;
1294 WIN_ReleaseWndPtr( ptr );
1299 /* Send destroy messages */
1301 WIN_SendDestroyMsg( hwnd );
1302 if (!IsWindow(hwnd))
1304 retvalue = TRUE;
1305 goto end;
1308 /* Unlink now so we won't bother with the children later on */
1310 if( wndPtr->parent ) WIN_UnlinkWindow(hwnd);
1312 /* Destroy the window storage */
1314 WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr ));
1315 retvalue = TRUE;
1316 end:
1317 WIN_ReleaseWndPtr(wndPtr);
1318 return retvalue;
1322 /***********************************************************************
1323 * CloseWindow (USER32.@)
1325 BOOL WINAPI CloseWindow( HWND hwnd )
1327 WND * wndPtr = WIN_FindWndPtr( hwnd );
1328 BOOL retvalue;
1330 if (!wndPtr || (wndPtr->dwStyle & WS_CHILD))
1332 retvalue = FALSE;
1333 goto end;
1335 ShowWindow( hwnd, SW_MINIMIZE );
1336 retvalue = TRUE;
1337 end:
1338 WIN_ReleaseWndPtr(wndPtr);
1339 return retvalue;
1344 /***********************************************************************
1345 * OpenIcon (USER32.@)
1347 BOOL WINAPI OpenIcon( HWND hwnd )
1349 if (!IsIconic( hwnd )) return FALSE;
1350 ShowWindow( hwnd, SW_SHOWNORMAL );
1351 return TRUE;
1355 /***********************************************************************
1356 * WIN_FindWindow
1358 * Implementation of FindWindow() and FindWindowEx().
1360 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1362 HWND *list;
1363 HWND retvalue;
1364 int i = 0, len = 0;
1365 WCHAR *buffer = NULL;
1367 if (!parent) parent = GetDesktopWindow();
1368 if (title)
1370 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1371 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1374 if (!(list = WIN_ListChildren( parent )))
1376 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1377 return 0;
1380 if (child)
1382 child = WIN_GetFullHandle( child );
1383 while (list[i] && list[i] != child) i++;
1384 if (!list[i]) return 0;
1385 i++; /* start from next window */
1388 for ( ; list[i]; i++)
1390 if (className && (GetClassWord(list[i], GCW_ATOM) != className))
1391 continue; /* Not the right class */
1393 /* Now check the title */
1394 if (!title) break;
1395 if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1397 retvalue = list[i];
1398 HeapFree( GetProcessHeap(), 0, list );
1399 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1401 /* In this case we need to check whether other processes
1402 own a window with the given paramters on the Desktop,
1403 but we don't, so let's at least warn about it */
1404 if (!retvalue) FIXME("Returning 0 without checking other processes\n");
1405 return retvalue;
1410 /***********************************************************************
1411 * FindWindowA (USER32.@)
1413 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1415 HWND ret = FindWindowExA( 0, 0, className, title );
1416 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1417 return ret;
1421 /***********************************************************************
1422 * FindWindowExA (USER32.@)
1424 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1425 LPCSTR className, LPCSTR title )
1427 ATOM atom = 0;
1428 LPWSTR buffer;
1429 HWND hwnd;
1431 if (className)
1433 /* If the atom doesn't exist, then no class */
1434 /* with this name exists either. */
1435 if (!(atom = GlobalFindAtomA( className )))
1437 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1438 return 0;
1442 buffer = HEAP_strdupAtoW( GetProcessHeap(), 0, title );
1443 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1444 HeapFree( GetProcessHeap(), 0, buffer );
1445 return hwnd;
1449 /***********************************************************************
1450 * FindWindowExW (USER32.@)
1452 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1453 LPCWSTR className, LPCWSTR title )
1455 ATOM atom = 0;
1457 if (className)
1459 /* If the atom doesn't exist, then no class */
1460 /* with this name exists either. */
1461 if (!(atom = GlobalFindAtomW( className )))
1463 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1464 return 0;
1467 return WIN_FindWindow( parent, child, atom, title );
1471 /***********************************************************************
1472 * FindWindowW (USER32.@)
1474 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1476 return FindWindowExW( 0, 0, className, title );
1480 /**********************************************************************
1481 * GetDesktopWindow (USER32.@)
1483 HWND WINAPI GetDesktopWindow(void)
1485 if (pWndDesktop) return pWndDesktop->hwndSelf;
1486 ERR( "You need the -desktop option when running with native USER\n" );
1487 ExitProcess(1);
1488 return 0;
1492 /*******************************************************************
1493 * EnableWindow (USER32.@)
1495 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1497 WND *wndPtr;
1498 BOOL retvalue;
1500 TRACE("( %x, %d )\n", hwnd, enable);
1502 if (USER_Driver.pEnableWindow)
1503 return USER_Driver.pEnableWindow( hwnd, enable );
1505 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1506 hwnd = wndPtr->hwndSelf; /* make it a full handle */
1508 retvalue = ((wndPtr->dwStyle & WS_DISABLED) != 0);
1510 if (enable && (wndPtr->dwStyle & WS_DISABLED))
1512 wndPtr->dwStyle &= ~WS_DISABLED; /* Enable window */
1513 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1515 else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
1517 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1519 wndPtr->dwStyle |= WS_DISABLED; /* Disable window */
1521 if (hwnd == GetFocus())
1522 SetFocus( 0 ); /* A disabled window can't have the focus */
1524 if (hwnd == GetCapture())
1525 ReleaseCapture(); /* A disabled window can't capture the mouse */
1527 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1529 WIN_ReleaseWndPtr(wndPtr);
1530 return retvalue;
1534 /***********************************************************************
1535 * IsWindowEnabled (USER32.@)
1537 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1539 WND * wndPtr;
1540 BOOL retvalue;
1542 if (!(wndPtr = WIN_FindWndPtr(hWnd))) return FALSE;
1543 retvalue = !(wndPtr->dwStyle & WS_DISABLED);
1544 WIN_ReleaseWndPtr(wndPtr);
1545 return retvalue;
1550 /***********************************************************************
1551 * IsWindowUnicode (USER32.@)
1553 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1555 WND * wndPtr;
1556 BOOL retvalue;
1558 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1559 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1560 WIN_ReleaseWndPtr(wndPtr);
1561 return retvalue;
1565 /**********************************************************************
1566 * GetWindowWord (USER32.@)
1568 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1570 WORD retvalue;
1571 WND * wndPtr = WIN_FindWndPtr( hwnd );
1572 if (!wndPtr) return 0;
1573 if (offset >= 0)
1575 if (offset + sizeof(WORD) > wndPtr->cbWndExtra)
1577 WARN("Invalid offset %d\n", offset );
1578 retvalue = 0;
1580 else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1581 WIN_ReleaseWndPtr(wndPtr);
1582 return retvalue;
1585 WIN_ReleaseWndPtr(wndPtr);
1586 switch(offset)
1588 case GWL_HWNDPARENT:
1589 return GetWindowLongW( hwnd, offset );
1590 case GWL_ID:
1591 case GWL_HINSTANCE:
1593 LONG ret = GetWindowLongW( hwnd, offset );
1594 if (HIWORD(ret))
1595 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1596 return LOWORD(ret);
1598 default:
1599 WARN("Invalid offset %d\n", offset );
1600 return 0;
1605 /**********************************************************************
1606 * SetWindowWord (USER32.@)
1608 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1610 WORD *ptr, retval;
1611 WND * wndPtr = WIN_FindWndPtr( hwnd );
1612 if (!wndPtr) return 0;
1613 if (offset >= 0)
1615 if (offset + sizeof(WORD) > wndPtr->cbWndExtra)
1617 WARN("Invalid offset %d\n", offset );
1618 WIN_ReleaseWndPtr(wndPtr);
1619 return 0;
1621 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1622 retval = *ptr;
1623 *ptr = newval;
1624 WIN_ReleaseWndPtr(wndPtr);
1625 return retval;
1628 WIN_ReleaseWndPtr(wndPtr);
1629 switch(offset)
1631 case GWL_ID:
1632 case GWL_HINSTANCE:
1633 case GWL_HWNDPARENT:
1634 return SetWindowLongW( hwnd, offset, (UINT)newval );
1635 default:
1636 WARN("Invalid offset %d\n", offset );
1637 return 0;
1642 /**********************************************************************
1643 * WIN_GetWindowLong
1645 * Helper function for GetWindowLong().
1647 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1649 LONG retvalue;
1650 WND * wndPtr = WIN_FindWndPtr( hwnd );
1651 if (!wndPtr) return 0;
1652 if (offset >= 0)
1654 if (offset + sizeof(LONG) > wndPtr->cbWndExtra)
1656 WARN("Invalid offset %d\n", offset );
1657 retvalue = 0;
1658 goto end;
1660 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1661 /* Special case for dialog window procedure */
1662 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1664 retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1665 goto end;
1667 goto end;
1669 switch(offset)
1671 case GWL_USERDATA: retvalue = wndPtr->userdata;
1672 goto end;
1673 case GWL_STYLE: retvalue = wndPtr->dwStyle;
1674 goto end;
1675 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle;
1676 goto end;
1677 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu;
1678 goto end;
1679 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc,
1680 type );
1681 goto end;
1682 case GWL_HWNDPARENT: retvalue = (LONG)GetParent(hwnd);
1683 goto end;
1684 case GWL_HINSTANCE: retvalue = wndPtr->hInstance;
1685 goto end;
1686 default:
1687 WARN("Unknown offset %d\n", offset );
1689 retvalue = 0;
1690 end:
1691 WIN_ReleaseWndPtr(wndPtr);
1692 return retvalue;
1696 /**********************************************************************
1697 * WIN_SetWindowLong
1699 * Helper function for SetWindowLong().
1701 * 0 is the failure code. However, in the case of failure SetLastError
1702 * must be set to distinguish between a 0 return value and a failure.
1704 * FIXME: The error values for SetLastError may not be right. Can
1705 * someone check with the real thing?
1707 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1708 WINDOWPROCTYPE type )
1710 LONG *ptr, retval;
1711 WND * wndPtr = WIN_FindWndPtr( hwnd );
1712 STYLESTRUCT style;
1714 TRACE("%x=%p %x %lx %x\n",hwnd, wndPtr, offset, newval, type);
1716 if (!wndPtr)
1718 /* Is this the right error? */
1719 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1720 return 0;
1723 if (offset >= 0)
1725 if (offset + sizeof(LONG) > wndPtr->cbWndExtra)
1727 WARN("Invalid offset %d\n", offset );
1729 /* Is this the right error? */
1730 SetLastError( ERROR_OUTOFMEMORY );
1732 retval = 0;
1733 goto end;
1735 ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1736 /* Special case for dialog window procedure */
1737 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1739 retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1740 WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
1741 type, WIN_PROC_WINDOW );
1742 goto end;
1745 else switch(offset)
1747 case GWL_ID:
1748 ptr = (DWORD*)&wndPtr->wIDmenu;
1749 break;
1750 case GWL_HINSTANCE:
1751 ptr = (DWORD*)&wndPtr->hInstance;
1752 break;
1753 case GWL_USERDATA:
1754 ptr = &wndPtr->userdata;
1755 break;
1756 case GWL_HWNDPARENT:
1757 retval = SetParent( hwnd, (HWND)newval );
1758 goto end;
1759 case GWL_WNDPROC:
1760 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
1761 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
1762 type, WIN_PROC_WINDOW );
1763 goto end;
1764 case GWL_STYLE:
1765 retval = wndPtr->dwStyle;
1766 style.styleOld = wndPtr->dwStyle;
1767 style.styleNew = newval;
1768 SendMessageA(hwnd,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style);
1769 wndPtr->dwStyle = style.styleNew;
1770 if (USER_Driver.pSetWindowStyle) USER_Driver.pSetWindowStyle( hwnd, retval );
1771 SendMessageA(hwnd,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style);
1772 retval = style.styleOld;
1773 goto end;
1774 case GWL_EXSTYLE:
1775 style.styleOld = wndPtr->dwExStyle;
1776 style.styleNew = newval;
1777 SendMessageA(hwnd,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style);
1778 wndPtr->dwExStyle = style.styleNew;
1779 SendMessageA(hwnd,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style);
1780 retval = style.styleOld;
1781 goto end;
1783 default:
1784 WARN("Invalid offset %d\n", offset );
1786 /* Don't think this is right error but it should do */
1787 SetLastError( ERROR_OUTOFMEMORY );
1789 retval = 0;
1790 goto end;
1792 retval = *ptr;
1793 *ptr = newval;
1794 end:
1795 WIN_ReleaseWndPtr(wndPtr);
1796 return retval;
1800 /**********************************************************************
1801 * GetWindowLong (USER.135)
1803 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
1805 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
1809 /**********************************************************************
1810 * GetWindowLongA (USER32.@)
1812 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
1814 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
1818 /**********************************************************************
1819 * GetWindowLongW (USER32.@)
1821 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
1823 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
1827 /**********************************************************************
1828 * SetWindowLong (USER.136)
1830 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
1832 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
1836 /**********************************************************************
1837 * SetWindowLongA (USER32.@)
1839 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
1841 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
1845 /**********************************************************************
1846 * SetWindowLongW (USER32.@) Set window attribute
1848 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
1849 * value in a window's extra memory.
1851 * The _hwnd_ parameter specifies the window. is the handle to a
1852 * window that has extra memory. The _newval_ parameter contains the
1853 * new attribute or extra memory value. If positive, the _offset_
1854 * parameter is the byte-addressed location in the window's extra
1855 * memory to set. If negative, _offset_ specifies the window
1856 * attribute to set, and should be one of the following values:
1858 * GWL_EXSTYLE The window's extended window style
1860 * GWL_STYLE The window's window style.
1862 * GWL_WNDPROC Pointer to the window's window procedure.
1864 * GWL_HINSTANCE The window's pplication instance handle.
1866 * GWL_ID The window's identifier.
1868 * GWL_USERDATA The window's user-specified data.
1870 * If the window is a dialog box, the _offset_ parameter can be one of
1871 * the following values:
1873 * DWL_DLGPROC The address of the window's dialog box procedure.
1875 * DWL_MSGRESULT The return value of a message
1876 * that the dialog box procedure processed.
1878 * DWL_USER Application specific information.
1880 * RETURNS
1882 * If successful, returns the previous value located at _offset_. Otherwise,
1883 * returns 0.
1885 * NOTES
1887 * Extra memory for a window class is specified by a nonzero cbWndExtra
1888 * parameter of the WNDCLASS structure passed to RegisterClass() at the
1889 * time of class creation.
1891 * Using GWL_WNDPROC to set a new window procedure effectively creates
1892 * a window subclass. Use CallWindowProc() in the new windows procedure
1893 * to pass messages to the superclass's window procedure.
1895 * The user data is reserved for use by the application which created
1896 * the window.
1898 * Do not use GWL_STYLE to change the window's WS_DISABLE style;
1899 * instead, call the EnableWindow() function to change the window's
1900 * disabled state.
1902 * Do not use GWL_HWNDPARENT to reset the window's parent, use
1903 * SetParent() instead.
1905 * Win95:
1906 * When offset is GWL_STYLE and the calling app's ver is 4.0,
1907 * it sends WM_STYLECHANGING before changing the settings
1908 * and WM_STYLECHANGED afterwards.
1909 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
1911 * BUGS
1913 * GWL_STYLE does not dispatch WM_STYLE... messages.
1915 * CONFORMANCE
1917 * ECMA-234, Win32
1920 LONG WINAPI SetWindowLongW(
1921 HWND hwnd, /* [in] window to alter */
1922 INT offset, /* [in] offset, in bytes, of location to alter */
1923 LONG newval /* [in] new value of location */
1925 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
1929 /*******************************************************************
1930 * GetWindowTextA (USER32.@)
1932 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
1934 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount,
1935 (LPARAM)lpString );
1938 /*******************************************************************
1939 * InternalGetWindowText (USER32.@)
1941 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
1943 WND *win = WIN_FindWndPtr( hwnd );
1944 if (!win) return 0;
1945 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
1946 else lpString[0] = 0;
1947 WIN_ReleaseWndPtr( win );
1948 return strlenW(lpString);
1952 /*******************************************************************
1953 * GetWindowTextW (USER32.@)
1955 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
1957 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount,
1958 (LPARAM)lpString );
1962 /*******************************************************************
1963 * SetWindowText (USER32.@)
1964 * SetWindowTextA (USER32.@)
1966 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
1968 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1972 /*******************************************************************
1973 * SetWindowTextW (USER32.@)
1975 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
1977 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1981 /*******************************************************************
1982 * GetWindowTextLengthA (USER32.@)
1984 INT WINAPI GetWindowTextLengthA( HWND hwnd )
1986 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1989 /*******************************************************************
1990 * GetWindowTextLengthW (USER32.@)
1992 INT WINAPI GetWindowTextLengthW( HWND hwnd )
1994 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1998 /*******************************************************************
1999 * IsWindow (USER32.@)
2001 BOOL WINAPI IsWindow( HWND hwnd )
2003 WND *ptr;
2004 BOOL ret;
2006 if ((ptr = get_wnd_ptr( hwnd )))
2008 if (ptr == BAD_WND_PTR) return FALSE;
2009 USER_Unlock();
2010 return TRUE;
2013 /* check other processes */
2014 SERVER_START_REQ( get_window_info )
2016 req->handle = hwnd;
2017 ret = !SERVER_CALL_ERR();
2019 SERVER_END_REQ;
2020 return ret;
2024 /***********************************************************************
2025 * GetWindowThreadProcessId (USER32.@)
2027 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2029 WND *ptr;
2030 DWORD tid = 0;
2032 if ((ptr = get_wnd_ptr( hwnd )))
2034 if (ptr != BAD_WND_PTR)
2036 /* got a valid window */
2037 tid = ptr->tid;
2038 if (process) *process = GetCurrentProcessId();
2039 USER_Unlock();
2041 else SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2042 return tid;
2045 /* check other processes */
2046 SERVER_START_REQ( get_window_info )
2048 req->handle = hwnd;
2049 if (!SERVER_CALL_ERR())
2051 tid = (DWORD)req->tid;
2052 if (process) *process = (DWORD)req->pid;
2055 SERVER_END_REQ;
2056 return tid;
2060 /*****************************************************************
2061 * GetParent (USER32.@)
2063 HWND WINAPI GetParent( HWND hwnd )
2065 WND *wndPtr;
2066 HWND retvalue = 0;
2068 if ((wndPtr = WIN_FindWndPtr(hwnd)))
2070 if (wndPtr->dwStyle & WS_CHILD)
2071 retvalue = wndPtr->parent->hwndSelf;
2072 else if (wndPtr->dwStyle & WS_POPUP)
2073 retvalue = wndPtr->owner;
2074 WIN_ReleaseWndPtr(wndPtr);
2076 return retvalue;
2080 /*****************************************************************
2081 * GetAncestor (USER32.@)
2083 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2085 HWND ret = 0;
2086 WND *wndPtr;
2088 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2089 if (wndPtr->hwndSelf == GetDesktopWindow()) goto done;
2091 switch(type)
2093 case GA_PARENT:
2094 WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2095 break;
2096 case GA_ROOT:
2097 while (wndPtr->parent->hwndSelf != GetDesktopWindow())
2098 WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2099 break;
2100 case GA_ROOTOWNER:
2101 while (wndPtr->parent->hwndSelf != GetDesktopWindow())
2102 WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2103 while (wndPtr && wndPtr->owner)
2105 WND *ptr = WIN_FindWndPtr( wndPtr->owner );
2106 WIN_ReleaseWndPtr( wndPtr );
2107 wndPtr = ptr;
2109 break;
2111 ret = wndPtr ? wndPtr->hwndSelf : 0;
2112 done:
2113 WIN_ReleaseWndPtr( wndPtr );
2114 return ret;
2118 /*****************************************************************
2119 * SetParent (USER32.@)
2121 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2123 WND *wndPtr;
2124 DWORD dwStyle;
2125 HWND retvalue;
2127 if (!parent) parent = GetDesktopWindow();
2128 else parent = WIN_GetFullHandle( parent );
2130 /* sanity checks */
2131 if (WIN_GetFullHandle(hwnd) == GetDesktopWindow() || !IsWindow( parent ))
2133 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2134 return 0;
2137 if (USER_Driver.pSetParent)
2138 return USER_Driver.pSetParent( hwnd, parent );
2140 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2142 dwStyle = wndPtr->dwStyle;
2144 /* Windows hides the window first, then shows it again
2145 * including the WM_SHOWWINDOW messages and all */
2146 if (dwStyle & WS_VISIBLE) ShowWindow( hwnd, SW_HIDE );
2148 retvalue = wndPtr->parent->hwndSelf; /* old parent */
2149 if (parent != retvalue)
2151 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2153 if (parent != GetDesktopWindow()) /* a child window */
2155 if (!(dwStyle & WS_CHILD))
2157 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2158 if (menu) DestroyMenu( menu );
2162 WIN_ReleaseWndPtr( wndPtr );
2164 /* SetParent additionally needs to make hwnd the topmost window
2165 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2166 WM_WINDOWPOSCHANGED notification messages.
2168 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2169 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|
2170 ((dwStyle & WS_VISIBLE)?SWP_SHOWWINDOW:0));
2171 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2172 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2173 return retvalue;
2177 /*******************************************************************
2178 * IsChild (USER32.@)
2180 BOOL WINAPI IsChild( HWND parent, HWND child )
2182 HWND *list = WIN_ListParents( child );
2183 int i;
2184 BOOL ret;
2186 if (!list) return FALSE;
2187 parent = WIN_GetFullHandle( parent );
2188 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2189 ret = (list[i] != 0);
2190 HeapFree( GetProcessHeap(), 0, list );
2191 return ret;
2195 /***********************************************************************
2196 * IsWindowVisible (USER32.@)
2198 BOOL WINAPI IsWindowVisible( HWND hwnd )
2200 HWND *list;
2201 BOOL retval;
2202 int i;
2204 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2205 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2206 for (i = 0; list[i]; i++)
2207 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2208 retval = !list[i];
2209 HeapFree( GetProcessHeap(), 0, list );
2210 return retval;
2214 /***********************************************************************
2215 * WIN_IsWindowDrawable
2217 * hwnd is drawable when it is visible, all parents are not
2218 * minimized, and it is itself not minimized unless we are
2219 * trying to draw its default class icon.
2221 BOOL WIN_IsWindowDrawable( WND* wnd, BOOL icon )
2223 HWND *list;
2224 BOOL retval;
2225 int i;
2227 if (!(wnd->dwStyle & WS_VISIBLE)) return FALSE;
2228 if ((wnd->dwStyle & WS_MINIMIZE) &&
2229 icon && GetClassLongA( wnd->hwndSelf, GCL_HICON )) return FALSE;
2231 if (!(list = WIN_ListParents( wnd->hwndSelf ))) return TRUE;
2232 for (i = 0; list[i]; i++)
2233 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2234 break;
2235 retval = !list[i];
2236 HeapFree( GetProcessHeap(), 0, list );
2237 return retval;
2241 /*******************************************************************
2242 * GetTopWindow (USER32.@)
2244 HWND WINAPI GetTopWindow( HWND hwnd )
2246 if (!hwnd) hwnd = GetDesktopWindow();
2247 return GetWindow( hwnd, GW_CHILD );
2251 /*******************************************************************
2252 * GetWindow (USER32.@)
2254 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2256 HWND retval = 0;
2258 if (rel == GW_OWNER) /* special case: not fully supported in the server yet */
2260 WND *wndPtr = WIN_FindWndPtr( hwnd );
2261 if (!wndPtr) return 0;
2262 retval = wndPtr->owner;
2263 WIN_ReleaseWndPtr( wndPtr );
2264 return retval;
2267 SERVER_START_REQ( get_window_tree )
2269 req->handle = hwnd;
2270 if (!SERVER_CALL_ERR())
2272 switch(rel)
2274 case GW_HWNDFIRST:
2275 retval = req->first_sibling;
2276 break;
2277 case GW_HWNDLAST:
2278 retval = req->last_sibling;
2279 break;
2280 case GW_HWNDNEXT:
2281 retval = req->next_sibling;
2282 break;
2283 case GW_HWNDPREV:
2284 retval = req->prev_sibling;
2285 break;
2286 case GW_CHILD:
2287 retval = req->first_child;
2288 break;
2292 SERVER_END_REQ;
2293 return retval;
2297 /***********************************************************************
2298 * WIN_InternalShowOwnedPopups
2300 * Internal version of ShowOwnedPopups; Wine functions should use this
2301 * to avoid interfering with application calls to ShowOwnedPopups
2302 * and to make sure the application can't prevent showing/hiding.
2304 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2308 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2310 int count = 0;
2311 WND *pWnd;
2312 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2314 if (!win_array) return TRUE;
2317 * Show windows Lowest first, Highest last to preserve Z-Order
2319 while (win_array[count]) count++;
2320 while (--count >= 0)
2322 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2323 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2325 if (pWnd->dwStyle & WS_POPUP)
2327 if (fShow)
2329 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2330 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2333 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2335 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2336 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2339 else
2341 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2342 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2343 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2346 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2348 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2349 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2350 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2354 WIN_ReleaseWndPtr( pWnd );
2356 HeapFree( GetProcessHeap(), 0, win_array );
2358 return TRUE;
2361 /*******************************************************************
2362 * ShowOwnedPopups (USER32.@)
2364 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2366 int count = 0;
2367 WND *pWnd;
2368 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2370 if (!win_array) return TRUE;
2372 while (win_array[count]) count++;
2373 while (--count >= 0)
2375 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2376 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2378 if (pWnd->dwStyle & WS_POPUP)
2380 if (fShow)
2382 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2384 /* In Windows, ShowOwnedPopups(TRUE) generates
2385 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2386 * regardless of the state of the owner
2388 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2389 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2392 else
2394 if (IsWindowVisible(pWnd->hwndSelf))
2396 /* In Windows, ShowOwnedPopups(FALSE) generates
2397 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2398 * regardless of the state of the owner
2400 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2401 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2405 WIN_ReleaseWndPtr( pWnd );
2407 HeapFree( GetProcessHeap(), 0, win_array );
2408 return TRUE;
2412 /*******************************************************************
2413 * GetLastActivePopup (USER32.@)
2415 HWND WINAPI GetLastActivePopup( HWND hwnd )
2417 HWND retval;
2418 WND *wndPtr =WIN_FindWndPtr(hwnd);
2419 if (!wndPtr) return hwnd;
2420 retval = wndPtr->hwndLastActive;
2421 if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2422 WIN_ReleaseWndPtr(wndPtr);
2423 return retval;
2427 /*******************************************************************
2428 * WIN_ListParents
2430 * Build an array of all parents of a given window, starting with
2431 * the immediate parent. The array must be freed with HeapFree.
2432 * Returns NULL if window is a top-level window.
2434 HWND *WIN_ListParents( HWND hwnd )
2436 HWND *list = NULL;
2438 SERVER_START_VAR_REQ( get_window_parents, REQUEST_MAX_VAR_SIZE )
2440 req->handle = hwnd;
2441 if (!SERVER_CALL())
2443 user_handle_t *data = server_data_ptr(req);
2444 int i, count = server_data_size(req) / sizeof(*data);
2445 if (count && ((list = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(HWND) ))))
2447 for (i = 0; i < count; i++) list[i] = data[i];
2448 list[i] = 0;
2452 SERVER_END_VAR_REQ;
2453 return list;
2457 /*******************************************************************
2458 * WIN_ListChildren
2460 * Build an array of the children of a given window. The array must be
2461 * freed with HeapFree. Returns NULL when no windows are found.
2463 HWND *WIN_ListChildren( HWND hwnd )
2465 HWND *list = NULL;
2467 SERVER_START_VAR_REQ( get_window_children, REQUEST_MAX_VAR_SIZE )
2469 req->parent = hwnd;
2470 if (!SERVER_CALL())
2472 user_handle_t *data = server_data_ptr(req);
2473 int i, count = server_data_size(req) / sizeof(*data);
2474 if (count && ((list = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(HWND) ))))
2476 for (i = 0; i < count; i++) list[i] = data[i];
2477 list[i] = 0;
2481 SERVER_END_VAR_REQ;
2482 return list;
2486 /*******************************************************************
2487 * EnumWindows (USER32.@)
2489 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2491 HWND *list;
2492 BOOL ret = TRUE;
2493 int i, iWndsLocks;
2495 /* We have to build a list of all windows first, to avoid */
2496 /* unpleasant side-effects, for instance if the callback */
2497 /* function changes the Z-order of the windows. */
2499 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE;
2501 /* Now call the callback function for every window */
2503 iWndsLocks = WIN_SuspendWndsLock();
2504 for (i = 0; list[i]; i++)
2506 /* Make sure that the window still exists */
2507 if (!IsWindow( list[i] )) continue;
2508 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2510 WIN_RestoreWndsLock(iWndsLocks);
2511 HeapFree( GetProcessHeap(), 0, list );
2512 return ret;
2516 /**********************************************************************
2517 * EnumTaskWindows16 (USER.225)
2519 BOOL16 WINAPI EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
2520 LPARAM lParam )
2522 TDB *tdb = TASK_GetPtr( hTask );
2523 if (!tdb) return FALSE;
2524 return EnumThreadWindows( (DWORD)tdb->teb->tid, (WNDENUMPROC)func, lParam );
2528 /**********************************************************************
2529 * EnumThreadWindows (USER32.@)
2531 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2533 HWND *list;
2534 int i, iWndsLocks;
2536 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE;
2538 /* Now call the callback function for every window */
2540 iWndsLocks = WIN_SuspendWndsLock();
2541 for (i = 0; list[i]; i++)
2543 if (GetWindowThreadProcessId( list[i], NULL ) != id) continue;
2544 if (!func( list[i], lParam )) break;
2546 WIN_RestoreWndsLock(iWndsLocks);
2547 HeapFree( GetProcessHeap(), 0, list );
2548 return TRUE;
2552 /**********************************************************************
2553 * WIN_EnumChildWindows
2555 * Helper function for EnumChildWindows().
2557 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2559 HWND *childList;
2560 BOOL ret = FALSE;
2562 for ( ; *list; list++)
2564 /* Make sure that the window still exists */
2565 if (!IsWindow( *list )) continue;
2566 /* skip owned windows */
2567 if (GetWindow( *list, GW_OWNER )) continue;
2568 /* Build children list first */
2569 childList = WIN_ListChildren( *list );
2571 ret = func( *list, lParam );
2573 if (childList)
2575 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2576 HeapFree( GetProcessHeap(), 0, childList );
2578 if (!ret) return FALSE;
2580 return TRUE;
2584 /**********************************************************************
2585 * EnumChildWindows (USER32.@)
2587 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2589 HWND *list;
2590 int iWndsLocks;
2592 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2593 iWndsLocks = WIN_SuspendWndsLock();
2594 WIN_EnumChildWindows( list, func, lParam );
2595 WIN_RestoreWndsLock(iWndsLocks);
2596 HeapFree( GetProcessHeap(), 0, list );
2597 return TRUE;
2601 /*******************************************************************
2602 * AnyPopup (USER.52)
2604 BOOL16 WINAPI AnyPopup16(void)
2606 return AnyPopup();
2610 /*******************************************************************
2611 * AnyPopup (USER32.@)
2613 BOOL WINAPI AnyPopup(void)
2615 int i;
2616 BOOL retvalue;
2617 HWND *list = WIN_ListChildren( GetDesktopWindow() );
2619 if (!list) return FALSE;
2620 for (i = 0; list[i]; i++)
2622 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2624 retvalue = (list[i] != 0);
2625 HeapFree( GetProcessHeap(), 0, list );
2626 return retvalue;
2630 /*******************************************************************
2631 * FlashWindow (USER32.@)
2633 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2635 WND *wndPtr = WIN_FindWndPtr(hWnd);
2637 TRACE("%04x\n", hWnd);
2639 if (!wndPtr) return FALSE;
2640 hWnd = wndPtr->hwndSelf; /* make it a full handle */
2642 if (wndPtr->dwStyle & WS_MINIMIZE)
2644 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2646 HDC hDC = GetDC(hWnd);
2648 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
2649 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
2651 ReleaseDC( hWnd, hDC );
2652 wndPtr->flags |= WIN_NCACTIVATED;
2654 else
2656 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2657 wndPtr->flags &= ~WIN_NCACTIVATED;
2659 WIN_ReleaseWndPtr(wndPtr);
2660 return TRUE;
2662 else
2664 WPARAM16 wparam;
2665 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2666 else wparam = (hWnd == GetActiveWindow());
2668 WIN_ReleaseWndPtr(wndPtr);
2669 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2670 return wparam;
2675 /*******************************************************************
2676 * GetWindowContextHelpId (USER32.@)
2678 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
2680 DWORD retval;
2681 WND *wnd = WIN_FindWndPtr( hwnd );
2682 if (!wnd) return 0;
2683 retval = wnd->helpContext;
2684 WIN_ReleaseWndPtr(wnd);
2685 return retval;
2689 /*******************************************************************
2690 * SetWindowContextHelpId (USER32.@)
2692 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
2694 WND *wnd = WIN_FindWndPtr( hwnd );
2695 if (!wnd) return FALSE;
2696 wnd->helpContext = id;
2697 WIN_ReleaseWndPtr(wnd);
2698 return TRUE;
2702 /*******************************************************************
2703 * DRAG_QueryUpdate
2705 * recursively find a child that contains spDragInfo->pt point
2706 * and send WM_QUERYDROPOBJECT
2708 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
2710 BOOL16 wParam, bResult = 0;
2711 POINT pt;
2712 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
2713 RECT tempRect;
2715 if (!ptrDragInfo) return FALSE;
2717 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
2719 GetWindowRect(hQueryWnd,&tempRect);
2721 if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
2723 if (!IsIconic( hQueryWnd ))
2725 GetClientRect( hQueryWnd, &tempRect );
2726 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
2728 if (PtInRect( &tempRect, pt))
2730 int i;
2731 HWND *list = WIN_ListChildren( hQueryWnd );
2733 wParam = 0;
2735 if (list)
2737 for (i = 0; list[i]; i++)
2739 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
2741 GetWindowRect( list[i], &tempRect );
2742 if (PtInRect( &tempRect, pt )) break;
2745 if (list[i])
2747 if (IsWindowEnabled( list[i] ))
2748 bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
2750 HeapFree( GetProcessHeap(), 0, list );
2752 if(bResult) return bResult;
2754 else wParam = 1;
2756 else wParam = 1;
2758 ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
2760 ptrDragInfo->hScope = hQueryWnd;
2762 if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
2763 else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
2765 if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
2767 return bResult;
2771 /*******************************************************************
2772 * DragDetect (USER32.@)
2774 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
2776 MSG msg;
2777 RECT rect;
2779 rect.left = pt.x - wDragWidth;
2780 rect.right = pt.x + wDragWidth;
2782 rect.top = pt.y - wDragHeight;
2783 rect.bottom = pt.y + wDragHeight;
2785 SetCapture(hWnd);
2787 while(1)
2789 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
2791 if( msg.message == WM_LBUTTONUP )
2793 ReleaseCapture();
2794 return 0;
2796 if( msg.message == WM_MOUSEMOVE )
2798 POINT tmp;
2799 tmp.x = LOWORD(msg.lParam);
2800 tmp.y = HIWORD(msg.lParam);
2801 if( !PtInRect( &rect, tmp ))
2803 ReleaseCapture();
2804 return 1;
2808 WaitMessage();
2810 return 0;
2813 /******************************************************************************
2814 * DragObject (USER.464)
2816 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
2817 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
2819 MSG msg;
2820 LPDRAGINFO16 lpDragInfo;
2821 SEGPTR spDragInfo;
2822 HCURSOR16 hDragCursor=0, hOldCursor=0, hBummer=0;
2823 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
2824 HCURSOR16 hCurrentCursor = 0;
2825 HWND16 hCurrentWnd = 0;
2827 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
2828 spDragInfo = K32WOWGlobalLock16(hDragInfo);
2830 if( !lpDragInfo || !spDragInfo ) return 0L;
2832 if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
2834 GlobalFree16(hDragInfo);
2835 return 0L;
2838 if(hCursor)
2840 if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
2842 GlobalFree16(hDragInfo);
2843 return 0L;
2846 if( hDragCursor == hCursor ) hDragCursor = 0;
2847 else hCursor = hDragCursor;
2849 hOldCursor = SetCursor(hDragCursor);
2852 lpDragInfo->hWnd = hWnd;
2853 lpDragInfo->hScope = 0;
2854 lpDragInfo->wFlags = wObj;
2855 lpDragInfo->hList = szList; /* near pointer! */
2856 lpDragInfo->hOfStruct = hOfStruct;
2857 lpDragInfo->l = 0L;
2859 SetCapture(hWnd);
2860 ShowCursor( TRUE );
2864 GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
2866 *(lpDragInfo+1) = *lpDragInfo;
2868 lpDragInfo->pt.x = msg.pt.x;
2869 lpDragInfo->pt.y = msg.pt.y;
2871 /* update DRAGINFO struct */
2872 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
2874 if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
2875 hCurrentCursor = hCursor;
2876 else
2878 hCurrentCursor = hBummer;
2879 lpDragInfo->hScope = 0;
2881 if( hCurrentCursor )
2882 SetCursor(hCurrentCursor);
2884 /* send WM_DRAGLOOP */
2885 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
2886 (LPARAM) spDragInfo );
2887 /* send WM_DRAGSELECT or WM_DRAGMOVE */
2888 if( hCurrentWnd != lpDragInfo->hScope )
2890 if( hCurrentWnd )
2891 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
2892 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
2893 HIWORD(spDragInfo)) );
2894 hCurrentWnd = lpDragInfo->hScope;
2895 if( hCurrentWnd )
2896 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
2898 else
2899 if( hCurrentWnd )
2900 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
2902 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
2904 ReleaseCapture();
2905 ShowCursor( FALSE );
2907 if( hCursor )
2909 SetCursor( hOldCursor );
2910 if (hDragCursor) DestroyCursor( hDragCursor );
2913 if( hCurrentCursor != hBummer )
2914 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
2915 (WPARAM16)hWnd, (LPARAM)spDragInfo );
2916 else
2917 msg.lParam = 0;
2918 GlobalFree16(hDragInfo);
2920 return (DWORD)(msg.lParam);
2924 /******************************************************************************
2925 * GetWindowModuleFileNameA (USER32.@)
2927 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
2929 FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
2930 hwnd, lpszFileName, cchFileNameMax);
2931 return 0;
2934 /******************************************************************************
2935 * GetWindowModuleFileNameW (USER32.@)
2937 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
2939 FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
2940 hwnd, lpszFileName, cchFileNameMax);
2941 return 0;