Prevent calling null functions.
[wine/wine64.git] / windows / win.c
bloba080870bb947f8b158a270f7a0b15ef4ad182848
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 style.styleOld = wndPtr->dwStyle;
1766 style.styleNew = newval;
1767 SendMessageA(hwnd,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style);
1768 wndPtr->dwStyle = style.styleNew;
1769 SendMessageA(hwnd,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style);
1770 retval = style.styleOld;
1771 goto end;
1772 case GWL_EXSTYLE:
1773 style.styleOld = wndPtr->dwExStyle;
1774 style.styleNew = newval;
1775 SendMessageA(hwnd,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style);
1776 wndPtr->dwExStyle = style.styleNew;
1777 SendMessageA(hwnd,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style);
1778 retval = style.styleOld;
1779 goto end;
1781 default:
1782 WARN("Invalid offset %d\n", offset );
1784 /* Don't think this is right error but it should do */
1785 SetLastError( ERROR_OUTOFMEMORY );
1787 retval = 0;
1788 goto end;
1790 retval = *ptr;
1791 *ptr = newval;
1792 end:
1793 WIN_ReleaseWndPtr(wndPtr);
1794 return retval;
1798 /**********************************************************************
1799 * GetWindowLong (USER.135)
1801 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
1803 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
1807 /**********************************************************************
1808 * GetWindowLongA (USER32.@)
1810 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
1812 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
1816 /**********************************************************************
1817 * GetWindowLongW (USER32.@)
1819 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
1821 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
1825 /**********************************************************************
1826 * SetWindowLong (USER.136)
1828 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
1830 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
1834 /**********************************************************************
1835 * SetWindowLongA (USER32.@)
1837 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
1839 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
1843 /**********************************************************************
1844 * SetWindowLongW (USER32.@) Set window attribute
1846 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
1847 * value in a window's extra memory.
1849 * The _hwnd_ parameter specifies the window. is the handle to a
1850 * window that has extra memory. The _newval_ parameter contains the
1851 * new attribute or extra memory value. If positive, the _offset_
1852 * parameter is the byte-addressed location in the window's extra
1853 * memory to set. If negative, _offset_ specifies the window
1854 * attribute to set, and should be one of the following values:
1856 * GWL_EXSTYLE The window's extended window style
1858 * GWL_STYLE The window's window style.
1860 * GWL_WNDPROC Pointer to the window's window procedure.
1862 * GWL_HINSTANCE The window's pplication instance handle.
1864 * GWL_ID The window's identifier.
1866 * GWL_USERDATA The window's user-specified data.
1868 * If the window is a dialog box, the _offset_ parameter can be one of
1869 * the following values:
1871 * DWL_DLGPROC The address of the window's dialog box procedure.
1873 * DWL_MSGRESULT The return value of a message
1874 * that the dialog box procedure processed.
1876 * DWL_USER Application specific information.
1878 * RETURNS
1880 * If successful, returns the previous value located at _offset_. Otherwise,
1881 * returns 0.
1883 * NOTES
1885 * Extra memory for a window class is specified by a nonzero cbWndExtra
1886 * parameter of the WNDCLASS structure passed to RegisterClass() at the
1887 * time of class creation.
1889 * Using GWL_WNDPROC to set a new window procedure effectively creates
1890 * a window subclass. Use CallWindowProc() in the new windows procedure
1891 * to pass messages to the superclass's window procedure.
1893 * The user data is reserved for use by the application which created
1894 * the window.
1896 * Do not use GWL_STYLE to change the window's WS_DISABLE style;
1897 * instead, call the EnableWindow() function to change the window's
1898 * disabled state.
1900 * Do not use GWL_HWNDPARENT to reset the window's parent, use
1901 * SetParent() instead.
1903 * Win95:
1904 * When offset is GWL_STYLE and the calling app's ver is 4.0,
1905 * it sends WM_STYLECHANGING before changing the settings
1906 * and WM_STYLECHANGED afterwards.
1907 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
1909 * BUGS
1911 * GWL_STYLE does not dispatch WM_STYLE... messages.
1913 * CONFORMANCE
1915 * ECMA-234, Win32
1918 LONG WINAPI SetWindowLongW(
1919 HWND hwnd, /* [in] window to alter */
1920 INT offset, /* [in] offset, in bytes, of location to alter */
1921 LONG newval /* [in] new value of location */
1923 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
1927 /*******************************************************************
1928 * GetWindowTextA (USER32.@)
1930 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
1932 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount,
1933 (LPARAM)lpString );
1936 /*******************************************************************
1937 * InternalGetWindowText (USER32.@)
1939 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
1941 WND *win = WIN_FindWndPtr( hwnd );
1942 if (!win) return 0;
1943 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
1944 else lpString[0] = 0;
1945 WIN_ReleaseWndPtr( win );
1946 return strlenW(lpString);
1950 /*******************************************************************
1951 * GetWindowTextW (USER32.@)
1953 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
1955 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount,
1956 (LPARAM)lpString );
1960 /*******************************************************************
1961 * SetWindowText (USER32.@)
1962 * SetWindowTextA (USER32.@)
1964 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
1966 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1970 /*******************************************************************
1971 * SetWindowTextW (USER32.@)
1973 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
1975 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1979 /*******************************************************************
1980 * GetWindowTextLengthA (USER32.@)
1982 INT WINAPI GetWindowTextLengthA( HWND hwnd )
1984 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1987 /*******************************************************************
1988 * GetWindowTextLengthW (USER32.@)
1990 INT WINAPI GetWindowTextLengthW( HWND hwnd )
1992 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1996 /*******************************************************************
1997 * IsWindow (USER32.@)
1999 BOOL WINAPI IsWindow( HWND hwnd )
2001 WND *ptr;
2002 BOOL ret;
2004 if ((ptr = get_wnd_ptr( hwnd )))
2006 if (ptr == BAD_WND_PTR) return FALSE;
2007 USER_Unlock();
2008 return TRUE;
2011 /* check other processes */
2012 SERVER_START_REQ( get_window_info )
2014 req->handle = hwnd;
2015 ret = !SERVER_CALL_ERR();
2017 SERVER_END_REQ;
2018 return ret;
2022 /***********************************************************************
2023 * GetWindowThreadProcessId (USER32.@)
2025 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2027 WND *ptr;
2028 DWORD tid = 0;
2030 if ((ptr = get_wnd_ptr( hwnd )))
2032 if (ptr != BAD_WND_PTR)
2034 /* got a valid window */
2035 tid = ptr->tid;
2036 if (process) *process = GetCurrentProcessId();
2037 USER_Unlock();
2039 else SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2040 return tid;
2043 /* check other processes */
2044 SERVER_START_REQ( get_window_info )
2046 req->handle = hwnd;
2047 if (!SERVER_CALL_ERR())
2049 tid = (DWORD)req->tid;
2050 if (process) *process = (DWORD)req->pid;
2053 SERVER_END_REQ;
2054 return tid;
2058 /*****************************************************************
2059 * GetParent (USER32.@)
2061 HWND WINAPI GetParent( HWND hwnd )
2063 WND *wndPtr;
2064 HWND retvalue = 0;
2066 if ((wndPtr = WIN_FindWndPtr(hwnd)))
2068 if (wndPtr->dwStyle & WS_CHILD)
2069 retvalue = wndPtr->parent->hwndSelf;
2070 else if (wndPtr->dwStyle & WS_POPUP)
2071 retvalue = wndPtr->owner;
2072 WIN_ReleaseWndPtr(wndPtr);
2074 return retvalue;
2078 /*****************************************************************
2079 * GetAncestor (USER32.@)
2081 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2083 HWND ret = 0;
2084 WND *wndPtr;
2086 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2087 if (wndPtr->hwndSelf == GetDesktopWindow()) goto done;
2089 switch(type)
2091 case GA_PARENT:
2092 WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2093 break;
2094 case GA_ROOT:
2095 while (wndPtr->parent->hwndSelf != GetDesktopWindow())
2096 WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2097 break;
2098 case GA_ROOTOWNER:
2099 while (wndPtr->parent->hwndSelf != GetDesktopWindow())
2100 WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2101 while (wndPtr && wndPtr->owner)
2103 WND *ptr = WIN_FindWndPtr( wndPtr->owner );
2104 WIN_ReleaseWndPtr( wndPtr );
2105 wndPtr = ptr;
2107 break;
2109 ret = wndPtr ? wndPtr->hwndSelf : 0;
2110 done:
2111 WIN_ReleaseWndPtr( wndPtr );
2112 return ret;
2116 /*****************************************************************
2117 * SetParent (USER32.@)
2119 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2121 WND *wndPtr;
2122 DWORD dwStyle;
2123 HWND retvalue;
2125 if (!parent) parent = GetDesktopWindow();
2126 else parent = WIN_GetFullHandle( parent );
2128 /* sanity checks */
2129 if (WIN_GetFullHandle(hwnd) == GetDesktopWindow() || !IsWindow( parent ))
2131 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2132 return 0;
2135 if (USER_Driver.pSetParent)
2136 return USER_Driver.pSetParent( hwnd, parent );
2138 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2140 dwStyle = wndPtr->dwStyle;
2142 /* Windows hides the window first, then shows it again
2143 * including the WM_SHOWWINDOW messages and all */
2144 if (dwStyle & WS_VISIBLE) ShowWindow( hwnd, SW_HIDE );
2146 retvalue = wndPtr->parent->hwndSelf; /* old parent */
2147 if (parent != retvalue)
2149 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2151 if (parent != GetDesktopWindow()) /* a child window */
2153 if (!(dwStyle & WS_CHILD))
2155 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2156 if (menu) DestroyMenu( menu );
2160 WIN_ReleaseWndPtr( wndPtr );
2162 /* SetParent additionally needs to make hwnd the topmost window
2163 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2164 WM_WINDOWPOSCHANGED notification messages.
2166 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2167 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|
2168 ((dwStyle & WS_VISIBLE)?SWP_SHOWWINDOW:0));
2169 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2170 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2171 return retvalue;
2175 /*******************************************************************
2176 * IsChild (USER32.@)
2178 BOOL WINAPI IsChild( HWND parent, HWND child )
2180 HWND *list = WIN_ListParents( child );
2181 int i;
2182 BOOL ret;
2184 if (!list) return FALSE;
2185 parent = WIN_GetFullHandle( parent );
2186 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2187 ret = (list[i] != 0);
2188 HeapFree( GetProcessHeap(), 0, list );
2189 return ret;
2193 /***********************************************************************
2194 * IsWindowVisible (USER32.@)
2196 BOOL WINAPI IsWindowVisible( HWND hwnd )
2198 HWND *list;
2199 BOOL retval;
2200 int i;
2202 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2203 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2204 for (i = 0; list[i]; i++)
2205 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2206 retval = !list[i];
2207 HeapFree( GetProcessHeap(), 0, list );
2208 return retval;
2212 /***********************************************************************
2213 * WIN_IsWindowDrawable
2215 * hwnd is drawable when it is visible, all parents are not
2216 * minimized, and it is itself not minimized unless we are
2217 * trying to draw its default class icon.
2219 BOOL WIN_IsWindowDrawable( WND* wnd, BOOL icon )
2221 HWND *list;
2222 BOOL retval;
2223 int i;
2225 if (!(wnd->dwStyle & WS_VISIBLE)) return FALSE;
2226 if ((wnd->dwStyle & WS_MINIMIZE) &&
2227 icon && GetClassLongA( wnd->hwndSelf, GCL_HICON )) return FALSE;
2229 if (!(list = WIN_ListParents( wnd->hwndSelf ))) return TRUE;
2230 for (i = 0; list[i]; i++)
2231 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2232 break;
2233 retval = !list[i];
2234 HeapFree( GetProcessHeap(), 0, list );
2235 return retval;
2239 /*******************************************************************
2240 * GetTopWindow (USER32.@)
2242 HWND WINAPI GetTopWindow( HWND hwnd )
2244 if (!hwnd) hwnd = GetDesktopWindow();
2245 return GetWindow( hwnd, GW_CHILD );
2249 /*******************************************************************
2250 * GetWindow (USER32.@)
2252 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2254 HWND retval = 0;
2256 if (rel == GW_OWNER) /* special case: not fully supported in the server yet */
2258 WND *wndPtr = WIN_FindWndPtr( hwnd );
2259 if (!wndPtr) return 0;
2260 retval = wndPtr->owner;
2261 WIN_ReleaseWndPtr( wndPtr );
2262 return retval;
2265 SERVER_START_REQ( get_window_tree )
2267 req->handle = hwnd;
2268 if (!SERVER_CALL_ERR())
2270 switch(rel)
2272 case GW_HWNDFIRST:
2273 retval = req->first_sibling;
2274 break;
2275 case GW_HWNDLAST:
2276 retval = req->last_sibling;
2277 break;
2278 case GW_HWNDNEXT:
2279 retval = req->next_sibling;
2280 break;
2281 case GW_HWNDPREV:
2282 retval = req->prev_sibling;
2283 break;
2284 case GW_CHILD:
2285 retval = req->first_child;
2286 break;
2290 SERVER_END_REQ;
2291 return retval;
2295 /***********************************************************************
2296 * WIN_InternalShowOwnedPopups
2298 * Internal version of ShowOwnedPopups; Wine functions should use this
2299 * to avoid interfering with application calls to ShowOwnedPopups
2300 * and to make sure the application can't prevent showing/hiding.
2302 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2306 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2308 int count = 0;
2309 WND *pWnd;
2310 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2312 if (!win_array) return TRUE;
2315 * Show windows Lowest first, Highest last to preserve Z-Order
2317 while (win_array[count]) count++;
2318 while (--count >= 0)
2320 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2321 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2323 if (pWnd->dwStyle & WS_POPUP)
2325 if (fShow)
2327 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2328 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2331 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2333 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2334 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2337 else
2339 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2340 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2341 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2344 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2346 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2347 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2348 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2352 WIN_ReleaseWndPtr( pWnd );
2354 HeapFree( GetProcessHeap(), 0, win_array );
2356 return TRUE;
2359 /*******************************************************************
2360 * ShowOwnedPopups (USER32.@)
2362 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2364 int count = 0;
2365 WND *pWnd;
2366 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2368 if (!win_array) return TRUE;
2370 while (win_array[count]) count++;
2371 while (--count >= 0)
2373 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2374 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2376 if (pWnd->dwStyle & WS_POPUP)
2378 if (fShow)
2380 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2382 /* In Windows, ShowOwnedPopups(TRUE) generates
2383 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2384 * regardless of the state of the owner
2386 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2387 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2390 else
2392 if (IsWindowVisible(pWnd->hwndSelf))
2394 /* In Windows, ShowOwnedPopups(FALSE) generates
2395 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2396 * regardless of the state of the owner
2398 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2399 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2403 WIN_ReleaseWndPtr( pWnd );
2405 HeapFree( GetProcessHeap(), 0, win_array );
2406 return TRUE;
2410 /*******************************************************************
2411 * GetLastActivePopup (USER32.@)
2413 HWND WINAPI GetLastActivePopup( HWND hwnd )
2415 HWND retval;
2416 WND *wndPtr =WIN_FindWndPtr(hwnd);
2417 if (!wndPtr) return hwnd;
2418 retval = wndPtr->hwndLastActive;
2419 if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2420 WIN_ReleaseWndPtr(wndPtr);
2421 return retval;
2425 /*******************************************************************
2426 * WIN_ListParents
2428 * Build an array of all parents of a given window, starting with
2429 * the immediate parent. The array must be freed with HeapFree.
2430 * Returns NULL if window is a top-level window.
2432 HWND *WIN_ListParents( HWND hwnd )
2434 HWND *list = NULL;
2436 SERVER_START_VAR_REQ( get_window_parents, REQUEST_MAX_VAR_SIZE )
2438 req->handle = hwnd;
2439 if (!SERVER_CALL())
2441 user_handle_t *data = server_data_ptr(req);
2442 int i, count = server_data_size(req) / sizeof(*data);
2443 if (count && ((list = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(HWND) ))))
2445 for (i = 0; i < count; i++) list[i] = data[i];
2446 list[i] = 0;
2450 SERVER_END_VAR_REQ;
2451 return list;
2455 /*******************************************************************
2456 * WIN_ListChildren
2458 * Build an array of the children of a given window. The array must be
2459 * freed with HeapFree. Returns NULL when no windows are found.
2461 HWND *WIN_ListChildren( HWND hwnd )
2463 HWND *list = NULL;
2465 SERVER_START_VAR_REQ( get_window_children, REQUEST_MAX_VAR_SIZE )
2467 req->parent = hwnd;
2468 if (!SERVER_CALL())
2470 user_handle_t *data = server_data_ptr(req);
2471 int i, count = server_data_size(req) / sizeof(*data);
2472 if (count && ((list = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(HWND) ))))
2474 for (i = 0; i < count; i++) list[i] = data[i];
2475 list[i] = 0;
2479 SERVER_END_VAR_REQ;
2480 return list;
2484 /*******************************************************************
2485 * EnumWindows (USER32.@)
2487 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2489 HWND *list;
2490 BOOL ret = TRUE;
2491 int i, iWndsLocks;
2493 /* We have to build a list of all windows first, to avoid */
2494 /* unpleasant side-effects, for instance if the callback */
2495 /* function changes the Z-order of the windows. */
2497 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE;
2499 /* Now call the callback function for every window */
2501 iWndsLocks = WIN_SuspendWndsLock();
2502 for (i = 0; list[i]; i++)
2504 /* Make sure that the window still exists */
2505 if (!IsWindow( list[i] )) continue;
2506 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2508 WIN_RestoreWndsLock(iWndsLocks);
2509 HeapFree( GetProcessHeap(), 0, list );
2510 return ret;
2514 /**********************************************************************
2515 * EnumTaskWindows16 (USER.225)
2517 BOOL16 WINAPI EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
2518 LPARAM lParam )
2520 TDB *tdb = TASK_GetPtr( hTask );
2521 if (!tdb) return FALSE;
2522 return EnumThreadWindows( (DWORD)tdb->teb->tid, (WNDENUMPROC)func, lParam );
2526 /**********************************************************************
2527 * EnumThreadWindows (USER32.@)
2529 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2531 HWND *list;
2532 int i, iWndsLocks;
2534 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE;
2536 /* Now call the callback function for every window */
2538 iWndsLocks = WIN_SuspendWndsLock();
2539 for (i = 0; list[i]; i++)
2541 if (GetWindowThreadProcessId( list[i], NULL ) != id) continue;
2542 if (!func( list[i], lParam )) break;
2544 WIN_RestoreWndsLock(iWndsLocks);
2545 HeapFree( GetProcessHeap(), 0, list );
2546 return TRUE;
2550 /**********************************************************************
2551 * WIN_EnumChildWindows
2553 * Helper function for EnumChildWindows().
2555 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2557 HWND *childList;
2558 BOOL ret = FALSE;
2560 for ( ; *list; list++)
2562 /* Make sure that the window still exists */
2563 if (!IsWindow( *list )) continue;
2564 /* skip owned windows */
2565 if (GetWindow( *list, GW_OWNER )) continue;
2566 /* Build children list first */
2567 childList = WIN_ListChildren( *list );
2569 ret = func( *list, lParam );
2571 if (childList)
2573 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2574 HeapFree( GetProcessHeap(), 0, childList );
2576 if (!ret) return FALSE;
2578 return TRUE;
2582 /**********************************************************************
2583 * EnumChildWindows (USER32.@)
2585 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2587 HWND *list;
2588 int iWndsLocks;
2590 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2591 iWndsLocks = WIN_SuspendWndsLock();
2592 WIN_EnumChildWindows( list, func, lParam );
2593 WIN_RestoreWndsLock(iWndsLocks);
2594 HeapFree( GetProcessHeap(), 0, list );
2595 return TRUE;
2599 /*******************************************************************
2600 * AnyPopup (USER.52)
2602 BOOL16 WINAPI AnyPopup16(void)
2604 return AnyPopup();
2608 /*******************************************************************
2609 * AnyPopup (USER32.@)
2611 BOOL WINAPI AnyPopup(void)
2613 int i;
2614 BOOL retvalue;
2615 HWND *list = WIN_ListChildren( GetDesktopWindow() );
2617 if (!list) return FALSE;
2618 for (i = 0; list[i]; i++)
2620 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2622 retvalue = (list[i] != 0);
2623 HeapFree( GetProcessHeap(), 0, list );
2624 return retvalue;
2628 /*******************************************************************
2629 * FlashWindow (USER32.@)
2631 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2633 WND *wndPtr = WIN_FindWndPtr(hWnd);
2635 TRACE("%04x\n", hWnd);
2637 if (!wndPtr) return FALSE;
2638 hWnd = wndPtr->hwndSelf; /* make it a full handle */
2640 if (wndPtr->dwStyle & WS_MINIMIZE)
2642 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2644 HDC hDC = GetDC(hWnd);
2646 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
2647 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
2649 ReleaseDC( hWnd, hDC );
2650 wndPtr->flags |= WIN_NCACTIVATED;
2652 else
2654 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2655 wndPtr->flags &= ~WIN_NCACTIVATED;
2657 WIN_ReleaseWndPtr(wndPtr);
2658 return TRUE;
2660 else
2662 WPARAM16 wparam;
2663 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2664 else wparam = (hWnd == GetActiveWindow());
2666 WIN_ReleaseWndPtr(wndPtr);
2667 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2668 return wparam;
2673 /*******************************************************************
2674 * GetWindowContextHelpId (USER32.@)
2676 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
2678 DWORD retval;
2679 WND *wnd = WIN_FindWndPtr( hwnd );
2680 if (!wnd) return 0;
2681 retval = wnd->helpContext;
2682 WIN_ReleaseWndPtr(wnd);
2683 return retval;
2687 /*******************************************************************
2688 * SetWindowContextHelpId (USER32.@)
2690 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
2692 WND *wnd = WIN_FindWndPtr( hwnd );
2693 if (!wnd) return FALSE;
2694 wnd->helpContext = id;
2695 WIN_ReleaseWndPtr(wnd);
2696 return TRUE;
2700 /*******************************************************************
2701 * DRAG_QueryUpdate
2703 * recursively find a child that contains spDragInfo->pt point
2704 * and send WM_QUERYDROPOBJECT
2706 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
2708 BOOL16 wParam, bResult = 0;
2709 POINT pt;
2710 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
2711 RECT tempRect;
2713 if (!ptrDragInfo) return FALSE;
2715 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
2717 GetWindowRect(hQueryWnd,&tempRect);
2719 if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
2721 if (!IsIconic( hQueryWnd ))
2723 GetClientRect( hQueryWnd, &tempRect );
2724 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
2726 if (PtInRect( &tempRect, pt))
2728 int i;
2729 HWND *list = WIN_ListChildren( hQueryWnd );
2731 wParam = 0;
2733 if (list)
2735 for (i = 0; list[i]; i++)
2737 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
2739 GetWindowRect( list[i], &tempRect );
2740 if (PtInRect( &tempRect, pt )) break;
2743 if (list[i])
2745 if (IsWindowEnabled( list[i] ))
2746 bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
2748 HeapFree( GetProcessHeap(), 0, list );
2750 if(bResult) return bResult;
2752 else wParam = 1;
2754 else wParam = 1;
2756 ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
2758 ptrDragInfo->hScope = hQueryWnd;
2760 if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
2761 else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
2763 if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
2765 return bResult;
2769 /*******************************************************************
2770 * DragDetect (USER32.@)
2772 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
2774 MSG msg;
2775 RECT rect;
2777 rect.left = pt.x - wDragWidth;
2778 rect.right = pt.x + wDragWidth;
2780 rect.top = pt.y - wDragHeight;
2781 rect.bottom = pt.y + wDragHeight;
2783 SetCapture(hWnd);
2785 while(1)
2787 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
2789 if( msg.message == WM_LBUTTONUP )
2791 ReleaseCapture();
2792 return 0;
2794 if( msg.message == WM_MOUSEMOVE )
2796 POINT tmp;
2797 tmp.x = LOWORD(msg.lParam);
2798 tmp.y = HIWORD(msg.lParam);
2799 if( !PtInRect( &rect, tmp ))
2801 ReleaseCapture();
2802 return 1;
2806 WaitMessage();
2808 return 0;
2811 /******************************************************************************
2812 * DragObject (USER.464)
2814 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
2815 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
2817 MSG msg;
2818 LPDRAGINFO16 lpDragInfo;
2819 SEGPTR spDragInfo;
2820 HCURSOR16 hDragCursor=0, hOldCursor=0, hBummer=0;
2821 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
2822 HCURSOR16 hCurrentCursor = 0;
2823 HWND16 hCurrentWnd = 0;
2825 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
2826 spDragInfo = K32WOWGlobalLock16(hDragInfo);
2828 if( !lpDragInfo || !spDragInfo ) return 0L;
2830 if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
2832 GlobalFree16(hDragInfo);
2833 return 0L;
2836 if(hCursor)
2838 if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
2840 GlobalFree16(hDragInfo);
2841 return 0L;
2844 if( hDragCursor == hCursor ) hDragCursor = 0;
2845 else hCursor = hDragCursor;
2847 hOldCursor = SetCursor(hDragCursor);
2850 lpDragInfo->hWnd = hWnd;
2851 lpDragInfo->hScope = 0;
2852 lpDragInfo->wFlags = wObj;
2853 lpDragInfo->hList = szList; /* near pointer! */
2854 lpDragInfo->hOfStruct = hOfStruct;
2855 lpDragInfo->l = 0L;
2857 SetCapture(hWnd);
2858 ShowCursor( TRUE );
2862 GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
2864 *(lpDragInfo+1) = *lpDragInfo;
2866 lpDragInfo->pt.x = msg.pt.x;
2867 lpDragInfo->pt.y = msg.pt.y;
2869 /* update DRAGINFO struct */
2870 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
2872 if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
2873 hCurrentCursor = hCursor;
2874 else
2876 hCurrentCursor = hBummer;
2877 lpDragInfo->hScope = 0;
2879 if( hCurrentCursor )
2880 SetCursor(hCurrentCursor);
2882 /* send WM_DRAGLOOP */
2883 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
2884 (LPARAM) spDragInfo );
2885 /* send WM_DRAGSELECT or WM_DRAGMOVE */
2886 if( hCurrentWnd != lpDragInfo->hScope )
2888 if( hCurrentWnd )
2889 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
2890 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
2891 HIWORD(spDragInfo)) );
2892 hCurrentWnd = lpDragInfo->hScope;
2893 if( hCurrentWnd )
2894 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
2896 else
2897 if( hCurrentWnd )
2898 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
2900 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
2902 ReleaseCapture();
2903 ShowCursor( FALSE );
2905 if( hCursor )
2907 SetCursor( hOldCursor );
2908 if (hDragCursor) DestroyCursor( hDragCursor );
2911 if( hCurrentCursor != hBummer )
2912 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
2913 (WPARAM16)hWnd, (LPARAM)spDragInfo );
2914 else
2915 msg.lParam = 0;
2916 GlobalFree16(hDragInfo);
2918 return (DWORD)(msg.lParam);
2922 /******************************************************************************
2923 * GetWindowModuleFileNameA (USER32.@)
2925 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
2927 FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
2928 hwnd, lpszFileName, cchFileNameMax);
2929 return 0;
2932 /******************************************************************************
2933 * GetWindowModuleFileNameW (USER32.@)
2935 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
2937 FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
2938 hwnd, lpszFileName, cchFileNameMax);
2939 return 0;