Declare DeviceIoControl.
[wine/wine64.git] / windows / win.c
blob2ca2f7728d47d33eb6f3b5273a2137fc45e3b6c4
1 /*
2 * Window related functions
4 * Copyright 1993, 1994 Alexandre Julliard
5 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include "windef.h"
10 #include "wine/winbase16.h"
11 #include "wine/winuser16.h"
12 #include "wine/server.h"
13 #include "wine/unicode.h"
14 #include "win.h"
15 #include "heap.h"
16 #include "user.h"
17 #include "dce.h"
18 #include "controls.h"
19 #include "cursoricon.h"
20 #include "hook.h"
21 #include "message.h"
22 #include "queue.h"
23 #include "task.h"
24 #include "winpos.h"
25 #include "winerror.h"
26 #include "stackframe.h"
27 #include "debugtools.h"
29 DEFAULT_DEBUG_CHANNEL(win);
30 DECLARE_DEBUG_CHANNEL(msg);
32 /**********************************************************************/
34 /* Desktop window */
35 static WND *pWndDesktop = NULL;
37 static WORD wDragWidth = 4;
38 static WORD wDragHeight= 3;
40 static void *user_handles[65536];
42 /* thread safeness */
43 extern SYSLEVEL USER_SysLevel; /* FIXME */
45 /***********************************************************************
46 * WIN_SuspendWndsLock
48 * Suspend the lock on WND structures.
49 * Returns the number of locks suspended
51 int WIN_SuspendWndsLock( void )
53 int isuspendedLocks = _ConfirmSysLevel( &USER_SysLevel );
54 int count = isuspendedLocks;
56 while ( count-- > 0 )
57 _LeaveSysLevel( &USER_SysLevel );
59 return isuspendedLocks;
62 /***********************************************************************
63 * WIN_RestoreWndsLock
65 * Restore the suspended locks on WND structures
67 void WIN_RestoreWndsLock( int ipreviousLocks )
69 while ( ipreviousLocks-- > 0 )
70 _EnterSysLevel( &USER_SysLevel );
73 /***********************************************************************
74 * create_window_handle
76 * Create a window handle with the server.
78 static WND *create_window_handle( BOOL desktop, INT size )
80 BOOL res;
81 user_handle_t handle = 0;
82 WND *win = HeapAlloc( GetProcessHeap(), 0, size );
84 if (!win) return NULL;
86 USER_Lock();
88 if (desktop)
90 SERVER_START_REQ( create_desktop_window )
92 if ((res = !SERVER_CALL_ERR())) handle = req->handle;
94 SERVER_END_REQ;
96 else
98 SERVER_START_REQ( create_window )
100 if ((res = !SERVER_CALL_ERR())) handle = req->handle;
102 SERVER_END_REQ;
105 if (!res)
107 USER_Unlock();
108 HeapFree( GetProcessHeap(), 0, win );
109 return NULL;
111 user_handles[LOWORD(handle)] = win;
112 win->hwndSelf = handle;
113 win->dwMagic = WND_MAGIC;
114 win->irefCount = 1;
115 return win;
119 /***********************************************************************
120 * free_window_handle
122 * Free a window handle.
124 static WND *free_window_handle( HWND hwnd )
126 WND *ptr;
128 USER_Lock();
129 if ((ptr = user_handles[LOWORD(hwnd)]))
131 SERVER_START_REQ( destroy_window )
133 req->handle = hwnd;
134 if (!SERVER_CALL_ERR())
135 user_handles[LOWORD(hwnd)] = 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 * If ret value is non-NULL, the user lock is held.
153 static WND *get_wnd_ptr( HWND hwnd )
155 WND * ptr;
157 if (!hwnd) return NULL;
159 USER_Lock();
160 if ((ptr = user_handles[LOWORD(hwnd)]))
162 if (ptr->dwMagic == WND_MAGIC && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
163 return ptr;
165 USER_Unlock();
166 return NULL;
170 /***********************************************************************
171 * WIN_Handle32
173 * Convert a 16-bit window handle to a full 32-bit handle.
175 HWND WIN_Handle32( HWND16 hwnd16 )
177 WND *ptr;
178 HWND hwnd = (HWND)(ULONG_PTR)hwnd16;
180 if (hwnd16 <= 1 || hwnd16 == 0xffff) return hwnd;
181 /* do sign extension for -2 and -3 */
182 if (hwnd16 >= (HWND16)-3) return (HWND)(LONG_PTR)(INT16)hwnd16;
184 if ((ptr = get_wnd_ptr( hwnd )))
186 hwnd = ptr->hwndSelf;
187 USER_Unlock();
189 else /* may belong to another process */
191 SERVER_START_REQ( get_window_info )
193 req->handle = hwnd;
194 if (!SERVER_CALL_ERR()) hwnd = req->full_handle;
196 SERVER_END_REQ;
198 return hwnd;
202 /***********************************************************************
203 * WIN_FindWndPtr
205 * Return a pointer to the WND structure corresponding to a HWND.
207 WND * WIN_FindWndPtr( HWND hwnd )
209 WND * ptr;
211 if (!hwnd) return NULL;
213 if ((ptr = get_wnd_ptr( hwnd )))
215 /* increment destruction monitoring */
216 ptr->irefCount++;
217 return ptr;
220 /* check other processes */
221 if (IsWindow( hwnd ))
223 ERR( "window %04x belongs to other process\n", hwnd );
224 /* DbgBreakPoint(); */
226 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
227 return NULL;
231 /***********************************************************************
232 * WIN_LockWndPtr
234 * Use in case the wnd ptr is not initialized with WIN_FindWndPtr
235 * but by initWndPtr;
236 * Returns the locked initialisation pointer
238 WND *WIN_LockWndPtr(WND *initWndPtr)
240 if(!initWndPtr) return 0;
242 /* Lock all WND structures for thread safeness*/
243 USER_Lock();
244 /*and increment destruction monitoring*/
245 initWndPtr->irefCount++;
247 return initWndPtr;
251 /***********************************************************************
252 * WIN_ReleaseWndPtr
254 * Release the pointer to the WND structure.
256 void WIN_ReleaseWndPtr(WND *wndPtr)
258 if(!wndPtr) return;
260 /*Decrement destruction monitoring value*/
261 wndPtr->irefCount--;
262 /* Check if it's time to release the memory*/
263 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
265 /* Release memory */
266 free_window_handle( wndPtr->hwndSelf );
268 else if(wndPtr->irefCount < 0)
270 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
271 ERR("forgot a Lock on %p somewhere\n",wndPtr);
273 /*unlock all WND structures for thread safeness*/
274 USER_Unlock();
277 /***********************************************************************
278 * WIN_UpdateWndPtr
280 * Updates the value of oldPtr to newPtr.
282 void WIN_UpdateWndPtr(WND **oldPtr, WND *newPtr)
284 WND *tmpWnd = NULL;
286 tmpWnd = WIN_LockWndPtr(newPtr);
287 WIN_ReleaseWndPtr(*oldPtr);
288 *oldPtr = tmpWnd;
293 /***********************************************************************
294 * WIN_UnlinkWindow
296 * Remove a window from the siblings linked list.
298 void WIN_UnlinkWindow( HWND hwnd )
300 WIN_LinkWindow( hwnd, 0, 0 );
304 /***********************************************************************
305 * WIN_LinkWindow
307 * Insert a window into the siblings linked list.
308 * The window is inserted after the specified window, which can also
309 * be specified as HWND_TOP or HWND_BOTTOM.
310 * If parent is 0, window is unlinked from the tree.
312 void WIN_LinkWindow( HWND hwnd, HWND parent, HWND hwndInsertAfter )
314 WND *wndPtr, **ppWnd, *parentPtr = NULL;
315 BOOL ret;
317 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return;
318 if (parent && !(parentPtr = WIN_FindWndPtr( parent )))
320 WIN_ReleaseWndPtr(wndPtr);
321 return;
324 SERVER_START_REQ( link_window )
326 req->handle = hwnd;
327 req->parent = parent;
328 req->previous = hwndInsertAfter;
329 ret = !SERVER_CALL_ERR();
331 SERVER_END_REQ;
332 if (!ret) goto done;
334 /* first unlink it if it is linked */
335 if (wndPtr->parent)
337 ppWnd = &wndPtr->parent->child;
338 while (*ppWnd && *ppWnd != wndPtr) ppWnd = &(*ppWnd)->next;
339 if (*ppWnd) *ppWnd = wndPtr->next;
342 if (parentPtr)
344 wndPtr->parent = parentPtr;
345 if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM))
347 ppWnd = &parentPtr->child; /* Point to first sibling hwnd */
348 if (hwndInsertAfter == HWND_BOTTOM) /* Find last sibling hwnd */
349 while (*ppWnd) ppWnd = &(*ppWnd)->next;
351 else /* Normal case */
353 WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter );
354 if (!afterPtr) goto done;
355 ppWnd = &afterPtr->next;
356 WIN_ReleaseWndPtr(afterPtr);
358 wndPtr->next = *ppWnd;
359 *ppWnd = wndPtr;
361 else wndPtr->next = NULL; /* unlinked */
363 done:
364 WIN_ReleaseWndPtr( parentPtr );
365 WIN_ReleaseWndPtr( wndPtr );
369 /***********************************************************************
370 * WIN_FindWinToRepaint
372 * Find a window that needs repaint.
374 HWND WIN_FindWinToRepaint( HWND hwnd )
376 HWND hwndRet;
377 WND *pWnd;
379 /* Note: the desktop window never gets WM_PAINT messages
380 * The real reason why is because Windows DesktopWndProc
381 * does ValidateRgn inside WM_ERASEBKGND handler.
383 if (hwnd == GetDesktopWindow()) hwnd = 0;
385 pWnd = hwnd ? WIN_FindWndPtr(hwnd) : WIN_LockWndPtr(pWndDesktop->child);
387 for ( ; pWnd ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
389 if (!(pWnd->dwStyle & WS_VISIBLE)) continue;
390 if ((pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT)) &&
391 GetWindowThreadProcessId( pWnd->hwndSelf, NULL ) == GetCurrentThreadId())
392 break;
393 if (pWnd->child )
395 if ((hwndRet = WIN_FindWinToRepaint( pWnd->child->hwndSelf )) )
397 WIN_ReleaseWndPtr(pWnd);
398 return hwndRet;
403 if(!pWnd)
405 TRACE("nothing found\n");
406 return 0;
408 hwndRet = pWnd->hwndSelf;
410 /* look among siblings if we got a transparent window */
411 while (pWnd)
413 if (!(pWnd->dwExStyle & WS_EX_TRANSPARENT) &&
414 (pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT)) &&
415 GetWindowThreadProcessId( pWnd->hwndSelf, NULL ) == GetCurrentThreadId())
417 hwndRet = pWnd->hwndSelf;
418 WIN_ReleaseWndPtr(pWnd);
419 break;
421 WIN_UpdateWndPtr(&pWnd,pWnd->next);
423 TRACE("found %04x\n",hwndRet);
424 return hwndRet;
428 /***********************************************************************
429 * WIN_DestroyWindow
431 * Destroy storage associated to a window. "Internals" p.358
432 * returns a locked wndPtr->next
434 static WND* WIN_DestroyWindow( WND* wndPtr )
436 HWND hwnd = wndPtr->hwndSelf;
437 WND *pWnd;
439 TRACE("%04x\n", wndPtr->hwndSelf );
441 /* free child windows */
442 WIN_LockWndPtr(wndPtr->child);
443 while ((pWnd = wndPtr->child))
445 wndPtr->child = WIN_DestroyWindow( pWnd );
446 WIN_ReleaseWndPtr(pWnd);
450 * Clear the update region to make sure no WM_PAINT messages will be
451 * generated for this window while processing the WM_NCDESTROY.
453 RedrawWindow( wndPtr->hwndSelf, NULL, 0,
454 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
457 * Send the WM_NCDESTROY to the window being destroyed.
459 SendMessageA( wndPtr->hwndSelf, WM_NCDESTROY, 0, 0);
461 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
463 WINPOS_CheckInternalPos( hwnd );
464 if( hwnd == GetCapture()) ReleaseCapture();
466 /* free resources associated with the window */
468 TIMER_RemoveWindowTimers( wndPtr->hwndSelf );
469 PROPERTY_RemoveWindowProps( wndPtr );
471 /* toss stale messages from the queue */
473 QUEUE_CleanupWindow( hwnd );
474 wndPtr->hmemTaskQ = 0;
476 if (!(wndPtr->dwStyle & WS_CHILD))
477 if (wndPtr->wIDmenu)
479 DestroyMenu( wndPtr->wIDmenu );
480 wndPtr->wIDmenu = 0;
482 if (wndPtr->hSysMenu)
484 DestroyMenu( wndPtr->hSysMenu );
485 wndPtr->hSysMenu = 0;
487 USER_Driver.pDestroyWindow( wndPtr->hwndSelf );
488 DCE_FreeWindowDCE( wndPtr->hwndSelf ); /* Always do this to catch orphaned DCs */
489 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
490 CLASS_RemoveWindow( wndPtr->class );
491 wndPtr->class = NULL;
492 wndPtr->dwMagic = 0; /* Mark it as invalid */
494 WIN_UpdateWndPtr(&pWnd,wndPtr->next);
496 return pWnd;
499 /***********************************************************************
500 * WIN_DestroyThreadWindows
502 * Destroy all children of 'wnd' owned by the current thread.
503 * Return TRUE if something was done.
505 void WIN_DestroyThreadWindows( HWND hwnd )
507 HWND *list;
508 int i;
510 if (!(list = WIN_ListChildren( hwnd ))) return;
511 for (i = 0; list[i]; i++)
513 if (!IsWindow( list[i] )) continue;
514 if (GetWindowThreadProcessId( list[i], NULL ) == GetCurrentThreadId())
515 DestroyWindow( list[i] );
516 else
517 WIN_DestroyThreadWindows( list[i] );
519 HeapFree( GetProcessHeap(), 0, list );
522 /***********************************************************************
523 * WIN_CreateDesktopWindow
525 * Create the desktop window.
527 BOOL WIN_CreateDesktopWindow(void)
529 struct tagCLASS *class;
530 HWND hwndDesktop;
531 INT wndExtra;
532 DWORD clsStyle;
533 WNDPROC winproc;
534 DCE *dce;
535 CREATESTRUCTA cs;
537 TRACE("Creating desktop window\n");
540 if (!WINPOS_CreateInternalPosAtom() ||
541 !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
542 &wndExtra, &winproc, &clsStyle, &dce )))
543 return FALSE;
545 pWndDesktop = create_window_handle( TRUE, sizeof(WND) + wndExtra );
546 if (!pWndDesktop) return FALSE;
547 hwndDesktop = pWndDesktop->hwndSelf;
549 pWndDesktop->tid = 0; /* nobody owns the desktop */
550 pWndDesktop->next = NULL;
551 pWndDesktop->child = NULL;
552 pWndDesktop->parent = NULL;
553 pWndDesktop->owner = 0;
554 pWndDesktop->class = class;
555 pWndDesktop->hInstance = 0;
556 pWndDesktop->rectWindow.left = 0;
557 pWndDesktop->rectWindow.top = 0;
558 pWndDesktop->rectWindow.right = GetSystemMetrics(SM_CXSCREEN);
559 pWndDesktop->rectWindow.bottom = GetSystemMetrics(SM_CYSCREEN);
560 pWndDesktop->rectClient = pWndDesktop->rectWindow;
561 pWndDesktop->text = NULL;
562 pWndDesktop->hmemTaskQ = 0;
563 pWndDesktop->hrgnUpdate = 0;
564 pWndDesktop->hwndLastActive = hwndDesktop;
565 pWndDesktop->dwStyle = WS_VISIBLE | WS_CLIPCHILDREN |
566 WS_CLIPSIBLINGS;
567 pWndDesktop->dwExStyle = 0;
568 pWndDesktop->clsStyle = clsStyle;
569 pWndDesktop->dce = NULL;
570 pWndDesktop->pVScroll = NULL;
571 pWndDesktop->pHScroll = NULL;
572 pWndDesktop->pProp = NULL;
573 pWndDesktop->wIDmenu = 0;
574 pWndDesktop->helpContext = 0;
575 pWndDesktop->flags = 0;
576 pWndDesktop->hSysMenu = 0;
577 pWndDesktop->userdata = 0;
578 pWndDesktop->winproc = winproc;
579 pWndDesktop->cbWndExtra = wndExtra;
581 cs.lpCreateParams = NULL;
582 cs.hInstance = 0;
583 cs.hMenu = 0;
584 cs.hwndParent = 0;
585 cs.x = 0;
586 cs.y = 0;
587 cs.cx = pWndDesktop->rectWindow.right;
588 cs.cy = pWndDesktop->rectWindow.bottom;
589 cs.style = pWndDesktop->dwStyle;
590 cs.dwExStyle = pWndDesktop->dwExStyle;
591 cs.lpszName = NULL;
592 cs.lpszClass = DESKTOP_CLASS_ATOM;
594 if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE )) return FALSE;
596 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
597 WIN_ReleaseWndPtr( pWndDesktop );
598 return TRUE;
602 /***********************************************************************
603 * WIN_FixCoordinates
605 * Fix the coordinates - Helper for WIN_CreateWindowEx.
606 * returns default show mode in sw.
607 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
609 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
611 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
612 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
614 if (cs->style & (WS_CHILD | WS_POPUP))
616 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
617 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
619 else /* overlapped window */
621 STARTUPINFOA info;
623 GetStartupInfoA( &info );
625 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
627 /* Never believe Microsoft's documentation... CreateWindowEx doc says
628 * that if an overlapped window is created with WS_VISIBLE style bit
629 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
630 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
631 * reveals that
633 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
634 * 2) it does not ignore the y parameter as the docs claim; instead, it
635 * uses it as second parameter to ShowWindow() unless y is either
636 * CW_USEDEFAULT or CW_USEDEFAULT16.
638 * The fact that we didn't do 2) caused bogus windows pop up when wine
639 * was running apps that were using this obscure feature. Example -
640 * calc.exe that comes with Win98 (only Win98, it's different from
641 * the one that comes with Win95 and NT)
643 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
644 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
645 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
648 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
650 if (info.dwFlags & STARTF_USESIZE)
652 cs->cx = info.dwXSize;
653 cs->cy = info.dwYSize;
655 else /* if no other hint from the app, pick 3/4 of the screen real estate */
657 RECT r;
658 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
659 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
660 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
667 /***********************************************************************
668 * WIN_CreateWindowEx
670 * Implementation of CreateWindowEx().
672 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
673 WINDOWPROCTYPE type )
675 INT sw = SW_SHOW;
676 struct tagCLASS *classPtr;
677 WND *wndPtr;
678 HWND hwnd, hwndLinkAfter;
679 POINT maxSize, maxPos, minTrack, maxTrack;
680 INT wndExtra;
681 DWORD clsStyle;
682 WNDPROC winproc;
683 DCE *dce;
684 BOOL unicode = (type == WIN_PROC_32W);
686 TRACE("%s %s ex=%08lx style=%08lx %d,%d %dx%d parent=%04x menu=%04x inst=%08x params=%p\n",
687 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszName) : debugres_a(cs->lpszName),
688 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszClass) : debugres_a(cs->lpszClass),
689 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
690 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
692 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
693 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
695 /* Find the parent window */
697 if (cs->hwndParent)
699 /* Make sure parent is valid */
700 if (!IsWindow( cs->hwndParent ))
702 WARN("Bad parent %04x\n", cs->hwndParent );
703 return 0;
705 } else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP)) {
706 WARN("No parent for child window\n" );
707 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
710 /* Find the window class */
711 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
712 &wndExtra, &winproc, &clsStyle, &dce )))
714 WARN("Bad class '%s'\n", cs->lpszClass );
715 return 0;
718 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
720 /* Correct the window style - stage 1
722 * These are patches that appear to affect both the style loaded into the
723 * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
725 * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
726 * why does the user get to set it?
729 /* This has been tested for WS_CHILD | WS_VISIBLE. It has not been
730 * tested for WS_POPUP
732 if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
733 ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
734 (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
735 cs->dwExStyle |= WS_EX_WINDOWEDGE;
736 else
737 cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
739 /* Create the window structure */
741 if (!(wndPtr = create_window_handle( FALSE,
742 sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
744 TRACE("out of memory\n" );
745 return 0;
747 hwnd = wndPtr->hwndSelf;
749 /* Fill the window structure */
751 wndPtr->tid = GetCurrentThreadId();
752 wndPtr->next = NULL;
753 wndPtr->child = NULL;
755 if ((cs->style & WS_CHILD) && cs->hwndParent)
757 wndPtr->parent = WIN_FindWndPtr( cs->hwndParent );
758 wndPtr->owner = 0;
759 WIN_ReleaseWndPtr(wndPtr->parent);
761 else
763 wndPtr->parent = pWndDesktop;
764 if (!cs->hwndParent || (cs->hwndParent == pWndDesktop->hwndSelf))
765 wndPtr->owner = 0;
766 else
767 wndPtr->owner = GetAncestor( cs->hwndParent, GA_ROOT );
771 wndPtr->class = classPtr;
772 wndPtr->winproc = winproc;
773 wndPtr->hInstance = cs->hInstance;
774 wndPtr->text = NULL;
775 wndPtr->hmemTaskQ = InitThreadInput16( 0, 0 );
776 wndPtr->hrgnUpdate = 0;
777 wndPtr->hrgnWnd = 0;
778 wndPtr->hwndLastActive = hwnd;
779 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
780 wndPtr->dwExStyle = cs->dwExStyle;
781 wndPtr->clsStyle = clsStyle;
782 wndPtr->wIDmenu = 0;
783 wndPtr->helpContext = 0;
784 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
785 wndPtr->pVScroll = NULL;
786 wndPtr->pHScroll = NULL;
787 wndPtr->pProp = NULL;
788 wndPtr->userdata = 0;
789 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU)
790 ? MENU_GetSysMenu( hwnd, 0 ) : 0;
791 wndPtr->cbWndExtra = wndExtra;
793 if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
795 /* Call the WH_CBT hook */
797 hwndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
798 ? HWND_BOTTOM : HWND_TOP;
800 if (HOOK_IsHooked( WH_CBT ))
802 CBT_CREATEWNDA cbtc;
803 LRESULT ret;
805 cbtc.lpcs = cs;
806 cbtc.hwndInsertAfter = hwndLinkAfter;
807 ret = (type == WIN_PROC_32W) ? HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND,
808 (WPARAM)hwnd, (LPARAM)&cbtc)
809 : HOOK_CallHooksA(WH_CBT, HCBT_CREATEWND,
810 (WPARAM)hwnd, (LPARAM)&cbtc);
811 if (ret)
813 TRACE("CBT-hook returned 0\n");
814 free_window_handle( hwnd );
815 CLASS_RemoveWindow( classPtr );
816 hwnd = 0;
817 goto end;
821 /* Correct the window style - stage 2 */
823 if (!(cs->style & WS_CHILD))
825 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
826 if (!(cs->style & WS_POPUP))
828 wndPtr->dwStyle |= WS_CAPTION;
829 wndPtr->flags |= WIN_NEED_SIZE;
833 /* Get class or window DC if needed */
835 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
836 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
837 else wndPtr->dce = NULL;
839 /* Initialize the dimensions before sending WM_GETMINMAXINFO */
841 wndPtr->rectWindow.left = cs->x;
842 wndPtr->rectWindow.top = cs->y;
843 wndPtr->rectWindow.right = cs->x + cs->cx;
844 wndPtr->rectWindow.bottom = cs->y + cs->cy;
845 wndPtr->rectClient = wndPtr->rectWindow;
847 /* Send the WM_GETMINMAXINFO message and fix the size if needed */
849 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
851 WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
852 if (maxSize.x < cs->cx) cs->cx = maxSize.x;
853 if (maxSize.y < cs->cy) cs->cy = maxSize.y;
854 if (cs->cx < minTrack.x ) cs->cx = minTrack.x;
855 if (cs->cy < minTrack.y ) cs->cy = minTrack.y;
858 if (cs->cx < 0) cs->cx = 0;
859 if (cs->cy < 0) cs->cy = 0;
861 wndPtr->rectWindow.left = cs->x;
862 wndPtr->rectWindow.top = cs->y;
863 wndPtr->rectWindow.right = cs->x + cs->cx;
864 wndPtr->rectWindow.bottom = cs->y + cs->cy;
865 wndPtr->rectClient = wndPtr->rectWindow;
867 /* Set the window menu */
869 if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
871 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
872 else
874 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
875 if (menuName)
877 if (HIWORD(cs->hInstance))
878 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
879 else
880 cs->hMenu = LoadMenu16(cs->hInstance,menuName);
882 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
886 else wndPtr->wIDmenu = (UINT)cs->hMenu;
888 if (!USER_Driver.pCreateWindow( wndPtr->hwndSelf, cs, unicode))
890 WARN("aborted by WM_xxCREATE!\n");
891 WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr ));
892 CLASS_RemoveWindow( classPtr );
893 WIN_ReleaseWndPtr(wndPtr);
894 return 0;
897 if( (wndPtr->dwStyle & WS_CHILD) && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
899 /* Notify the parent window only */
901 SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
902 MAKEWPARAM(WM_CREATE, wndPtr->wIDmenu), (LPARAM)hwnd );
903 if( !IsWindow(hwnd) )
905 hwnd = 0;
906 goto end;
910 if (cs->style & WS_VISIBLE)
912 /* in case WS_VISIBLE got set in the meantime */
913 wndPtr->dwStyle &= ~WS_VISIBLE;
914 ShowWindow( hwnd, sw );
917 /* Call WH_SHELL hook */
919 if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
920 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0 );
922 TRACE("created window %04x\n", hwnd);
923 end:
924 WIN_ReleaseWndPtr(wndPtr);
925 return hwnd;
929 /***********************************************************************
930 * CreateWindow (USER.41)
932 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
933 DWORD style, INT16 x, INT16 y, INT16 width,
934 INT16 height, HWND16 parent, HMENU16 menu,
935 HINSTANCE16 instance, LPVOID data )
937 return CreateWindowEx16( 0, className, windowName, style,
938 x, y, width, height, parent, menu, instance, data );
942 /***********************************************************************
943 * CreateWindowEx (USER.452)
945 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
946 LPCSTR windowName, DWORD style, INT16 x,
947 INT16 y, INT16 width, INT16 height,
948 HWND16 parent, HMENU16 menu,
949 HINSTANCE16 instance, LPVOID data )
951 ATOM classAtom;
952 CREATESTRUCTA cs;
953 char buffer[256];
955 /* Find the class atom */
957 if (HIWORD(className))
959 if (!(classAtom = GlobalFindAtomA( className )))
961 ERR( "bad class name %s\n", debugres_a(className) );
962 return 0;
965 else
967 classAtom = LOWORD(className);
968 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
970 ERR( "bad atom %x\n", classAtom);
971 return 0;
973 className = buffer;
976 /* Fix the coordinates */
978 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
979 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
980 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
981 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
983 /* Create the window */
985 cs.lpCreateParams = data;
986 cs.hInstance = (HINSTANCE)instance;
987 cs.hMenu = (HMENU)menu;
988 cs.hwndParent = WIN_Handle32( parent );
989 cs.style = style;
990 cs.lpszName = windowName;
991 cs.lpszClass = className;
992 cs.dwExStyle = exStyle;
994 return WIN_Handle16( WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 ));
998 /***********************************************************************
999 * CreateWindowExA (USER32.@)
1001 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1002 LPCSTR windowName, DWORD style, INT x,
1003 INT y, INT width, INT height,
1004 HWND parent, HMENU menu,
1005 HINSTANCE instance, LPVOID data )
1007 ATOM classAtom;
1008 CREATESTRUCTA cs;
1009 char buffer[256];
1011 if(!instance)
1012 instance=GetModuleHandleA(NULL);
1014 if(exStyle & WS_EX_MDICHILD)
1015 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1017 /* Find the class atom */
1019 if (HIWORD(className))
1021 if (!(classAtom = GlobalFindAtomA( className )))
1023 ERR( "bad class name %s\n", debugres_a(className) );
1024 return 0;
1027 else
1029 classAtom = LOWORD(className);
1030 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1032 ERR( "bad atom %x\n", classAtom);
1033 return 0;
1035 className = buffer;
1038 /* Create the window */
1040 cs.lpCreateParams = data;
1041 cs.hInstance = instance;
1042 cs.hMenu = menu;
1043 cs.hwndParent = parent;
1044 cs.x = x;
1045 cs.y = y;
1046 cs.cx = width;
1047 cs.cy = height;
1048 cs.style = style;
1049 cs.lpszName = windowName;
1050 cs.lpszClass = className;
1051 cs.dwExStyle = exStyle;
1053 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1057 /***********************************************************************
1058 * CreateWindowExW (USER32.@)
1060 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1061 LPCWSTR windowName, DWORD style, INT x,
1062 INT y, INT width, INT height,
1063 HWND parent, HMENU menu,
1064 HINSTANCE instance, LPVOID data )
1066 ATOM classAtom;
1067 CREATESTRUCTW cs;
1068 WCHAR buffer[256];
1070 if(!instance)
1071 instance=GetModuleHandleA(NULL);
1073 if(exStyle & WS_EX_MDICHILD)
1074 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1076 /* Find the class atom */
1078 if (HIWORD(className))
1080 if (!(classAtom = GlobalFindAtomW( className )))
1082 ERR( "bad class name %s\n", debugres_w(className) );
1083 return 0;
1086 else
1088 classAtom = LOWORD(className);
1089 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1091 ERR( "bad atom %x\n", classAtom);
1092 return 0;
1094 className = buffer;
1097 /* Create the window */
1099 cs.lpCreateParams = data;
1100 cs.hInstance = instance;
1101 cs.hMenu = menu;
1102 cs.hwndParent = parent;
1103 cs.x = x;
1104 cs.y = y;
1105 cs.cx = width;
1106 cs.cy = height;
1107 cs.style = style;
1108 cs.lpszName = windowName;
1109 cs.lpszClass = className;
1110 cs.dwExStyle = exStyle;
1112 /* Note: we rely on the fact that CREATESTRUCTA and */
1113 /* CREATESTRUCTW have the same layout. */
1114 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1118 /***********************************************************************
1119 * WIN_SendDestroyMsg
1121 static void WIN_SendDestroyMsg( HWND hwnd )
1123 if( CARET_GetHwnd() == hwnd) DestroyCaret();
1124 if (USER_Driver.pResetSelectionOwner)
1125 USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1128 * Send the WM_DESTROY to the window.
1130 SendMessageA( hwnd, WM_DESTROY, 0, 0);
1133 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1134 * make sure that the window still exists when we come back.
1136 if (IsWindow(hwnd))
1138 HWND* pWndArray;
1139 int i;
1141 if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1143 /* start from the end (FIXME: is this needed?) */
1144 for (i = 0; pWndArray[i]; i++) ;
1146 while (--i >= 0)
1148 if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1150 HeapFree( GetProcessHeap(), 0, pWndArray );
1152 else
1153 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1157 /***********************************************************************
1158 * DestroyWindow (USER32.@)
1160 BOOL WINAPI DestroyWindow( HWND hwnd )
1162 WND * wndPtr;
1163 BOOL retvalue;
1164 HWND h;
1166 hwnd = WIN_GetFullHandle( hwnd );
1167 TRACE("(%04x)\n", hwnd);
1169 /* Initialization */
1171 if (hwnd == GetDesktopWindow()) return FALSE; /* Can't destroy desktop */
1173 /* Look whether the focus is within the tree of windows we will
1174 * be destroying.
1176 h = GetFocus();
1177 if (h == hwnd || IsChild( hwnd, h ))
1179 HWND parent = GetAncestor( hwnd, GA_PARENT );
1180 if (parent == GetDesktopWindow()) parent = 0;
1181 SetFocus( parent );
1184 /* Call hooks */
1186 if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0L) ) return FALSE;
1188 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1189 if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
1191 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L );
1192 /* FIXME: clean up palette - see "Internals" p.352 */
1195 if( !QUEUE_IsExitingQueue(wndPtr->hmemTaskQ) )
1196 if( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
1198 /* Notify the parent window only */
1199 SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
1200 MAKEWPARAM(WM_DESTROY, wndPtr->wIDmenu), (LPARAM)hwnd );
1201 if( !IsWindow(hwnd) )
1203 retvalue = TRUE;
1204 goto end;
1208 if (USER_Driver.pResetSelectionOwner)
1209 USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1211 /* Hide the window */
1213 if (wndPtr->dwStyle & WS_VISIBLE)
1215 ShowWindow( hwnd, SW_HIDE );
1216 if (!IsWindow(hwnd))
1218 retvalue = TRUE;
1219 goto end;
1223 /* Recursively destroy owned windows */
1225 if( !(wndPtr->dwStyle & WS_CHILD) )
1227 for (;;)
1229 int i, got_one = 0;
1230 HWND *list = WIN_ListChildren( wndPtr->parent->hwndSelf );
1231 if (list)
1233 for (i = 0; list[i]; i++)
1235 WND *siblingPtr = WIN_FindWndPtr( list[i] );
1236 if (!siblingPtr) continue;
1237 if (siblingPtr->owner == hwnd)
1239 if (siblingPtr->hmemTaskQ == wndPtr->hmemTaskQ)
1241 WIN_ReleaseWndPtr( siblingPtr );
1242 DestroyWindow( list[i] );
1243 got_one = 1;
1244 continue;
1246 else siblingPtr->owner = 0;
1248 WIN_ReleaseWndPtr( siblingPtr );
1250 HeapFree( GetProcessHeap(), 0, list );
1252 if (!got_one) break;
1255 WINPOS_ActivateOtherWindow(wndPtr->hwndSelf);
1257 if (wndPtr->owner)
1259 WND *owner = WIN_FindWndPtr( wndPtr->owner );
1260 if (owner->hwndLastActive == hwnd) owner->hwndLastActive = wndPtr->owner;
1261 WIN_ReleaseWndPtr( owner );
1265 /* Send destroy messages */
1267 WIN_SendDestroyMsg( hwnd );
1268 if (!IsWindow(hwnd))
1270 retvalue = TRUE;
1271 goto end;
1274 /* Unlink now so we won't bother with the children later on */
1276 if( wndPtr->parent ) WIN_UnlinkWindow(hwnd);
1278 /* Destroy the window storage */
1280 WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr ));
1281 retvalue = TRUE;
1282 end:
1283 WIN_ReleaseWndPtr(wndPtr);
1284 return retvalue;
1288 /***********************************************************************
1289 * CloseWindow (USER32.@)
1291 BOOL WINAPI CloseWindow( HWND hwnd )
1293 WND * wndPtr = WIN_FindWndPtr( hwnd );
1294 BOOL retvalue;
1296 if (!wndPtr || (wndPtr->dwStyle & WS_CHILD))
1298 retvalue = FALSE;
1299 goto end;
1301 ShowWindow( hwnd, SW_MINIMIZE );
1302 retvalue = TRUE;
1303 end:
1304 WIN_ReleaseWndPtr(wndPtr);
1305 return retvalue;
1310 /***********************************************************************
1311 * OpenIcon (USER32.@)
1313 BOOL WINAPI OpenIcon( HWND hwnd )
1315 if (!IsIconic( hwnd )) return FALSE;
1316 ShowWindow( hwnd, SW_SHOWNORMAL );
1317 return TRUE;
1321 /***********************************************************************
1322 * WIN_FindWindow
1324 * Implementation of FindWindow() and FindWindowEx().
1326 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1328 HWND *list;
1329 HWND retvalue;
1330 int i = 0, len = 0;
1331 WCHAR *buffer = NULL;
1333 if (!parent) parent = GetDesktopWindow();
1334 if (title)
1336 len = strlenW(title) + 1; /* one extra char to check for chars beyond the end */
1337 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1340 if (!(list = WIN_ListChildren( parent )))
1342 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1343 return 0;
1346 if (child)
1348 child = WIN_GetFullHandle( child );
1349 while (list[i] && list[i] != child) i++;
1350 if (!list[i]) return 0;
1351 i++; /* start from next window */
1354 for ( ; list[i]; i++)
1356 if (className && (GetClassWord(list[i], GCW_ATOM) != className))
1357 continue; /* Not the right class */
1359 /* Now check the title */
1360 if (!title) break;
1361 if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1363 retvalue = list[i];
1364 HeapFree( GetProcessHeap(), 0, list );
1365 if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1367 /* In this case we need to check whether other processes
1368 own a window with the given paramters on the Desktop,
1369 but we don't, so let's at least warn about it */
1370 if (!retvalue) FIXME("Returning 0 without checking other processes\n");
1371 return retvalue;
1376 /***********************************************************************
1377 * FindWindowA (USER32.@)
1379 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1381 HWND ret = FindWindowExA( 0, 0, className, title );
1382 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1383 return ret;
1387 /***********************************************************************
1388 * FindWindowExA (USER32.@)
1390 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1391 LPCSTR className, LPCSTR title )
1393 ATOM atom = 0;
1394 LPWSTR buffer;
1395 HWND hwnd;
1397 if (className)
1399 /* If the atom doesn't exist, then no class */
1400 /* with this name exists either. */
1401 if (!(atom = GlobalFindAtomA( className )))
1403 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1404 return 0;
1408 buffer = HEAP_strdupAtoW( GetProcessHeap(), 0, title );
1409 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1410 HeapFree( GetProcessHeap(), 0, buffer );
1411 return hwnd;
1415 /***********************************************************************
1416 * FindWindowExW (USER32.@)
1418 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1419 LPCWSTR className, LPCWSTR title )
1421 ATOM atom = 0;
1423 if (className)
1425 /* If the atom doesn't exist, then no class */
1426 /* with this name exists either. */
1427 if (!(atom = GlobalFindAtomW( className )))
1429 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1430 return 0;
1433 return WIN_FindWindow( parent, child, atom, title );
1437 /***********************************************************************
1438 * FindWindowW (USER32.@)
1440 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1442 return FindWindowExW( 0, 0, className, title );
1446 /**********************************************************************
1447 * GetDesktopWindow (USER32.@)
1449 HWND WINAPI GetDesktopWindow(void)
1451 if (pWndDesktop) return pWndDesktop->hwndSelf;
1452 ERR( "You need the -desktop option when running with native USER\n" );
1453 ExitProcess(1);
1454 return 0;
1458 /*******************************************************************
1459 * EnableWindow (USER32.@)
1461 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1463 WND *wndPtr;
1464 BOOL retvalue;
1466 TRACE("( %x, %d )\n", hwnd, enable);
1468 if (USER_Driver.pEnableWindow)
1469 return USER_Driver.pEnableWindow( hwnd, enable );
1471 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1472 hwnd = wndPtr->hwndSelf; /* make it a full handle */
1474 retvalue = ((wndPtr->dwStyle & WS_DISABLED) != 0);
1476 if (enable && (wndPtr->dwStyle & WS_DISABLED))
1478 wndPtr->dwStyle &= ~WS_DISABLED; /* Enable window */
1479 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1481 else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
1483 SendMessageA( hwnd, WM_CANCELMODE, 0, 0);
1485 wndPtr->dwStyle |= WS_DISABLED; /* Disable window */
1487 if (hwnd == GetFocus())
1488 SetFocus( 0 ); /* A disabled window can't have the focus */
1490 if (hwnd == GetCapture())
1491 ReleaseCapture(); /* A disabled window can't capture the mouse */
1493 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1495 WIN_ReleaseWndPtr(wndPtr);
1496 return retvalue;
1500 /***********************************************************************
1501 * IsWindowEnabled (USER32.@)
1503 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1505 WND * wndPtr;
1506 BOOL retvalue;
1508 if (!(wndPtr = WIN_FindWndPtr(hWnd))) return FALSE;
1509 retvalue = !(wndPtr->dwStyle & WS_DISABLED);
1510 WIN_ReleaseWndPtr(wndPtr);
1511 return retvalue;
1516 /***********************************************************************
1517 * IsWindowUnicode (USER32.@)
1519 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1521 WND * wndPtr;
1522 BOOL retvalue;
1524 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1525 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1526 WIN_ReleaseWndPtr(wndPtr);
1527 return retvalue;
1531 /**********************************************************************
1532 * GetWindowWord (USER32.@)
1534 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1536 WORD retvalue;
1537 WND * wndPtr = WIN_FindWndPtr( hwnd );
1538 if (!wndPtr) return 0;
1539 if (offset >= 0)
1541 if (offset + sizeof(WORD) > wndPtr->cbWndExtra)
1543 WARN("Invalid offset %d\n", offset );
1544 retvalue = 0;
1546 else retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1547 WIN_ReleaseWndPtr(wndPtr);
1548 return retvalue;
1551 WIN_ReleaseWndPtr(wndPtr);
1552 switch(offset)
1554 case GWL_HWNDPARENT:
1555 return GetWindowLongW( hwnd, offset );
1556 case GWL_ID:
1557 case GWL_HINSTANCE:
1559 LONG ret = GetWindowLongW( hwnd, offset );
1560 if (HIWORD(ret))
1561 WARN("%d: discards high bits of 0x%08lx!\n", offset, ret );
1562 return LOWORD(ret);
1564 default:
1565 WARN("Invalid offset %d\n", offset );
1566 return 0;
1571 /**********************************************************************
1572 * SetWindowWord (USER32.@)
1574 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1576 WORD *ptr, retval;
1577 WND * wndPtr = WIN_FindWndPtr( hwnd );
1578 if (!wndPtr) return 0;
1579 if (offset >= 0)
1581 if (offset + sizeof(WORD) > wndPtr->cbWndExtra)
1583 WARN("Invalid offset %d\n", offset );
1584 WIN_ReleaseWndPtr(wndPtr);
1585 return 0;
1587 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1588 retval = *ptr;
1589 *ptr = newval;
1590 WIN_ReleaseWndPtr(wndPtr);
1591 return retval;
1594 WIN_ReleaseWndPtr(wndPtr);
1595 switch(offset)
1597 case GWL_ID:
1598 case GWL_HINSTANCE:
1599 case GWL_HWNDPARENT:
1600 return SetWindowLongW( hwnd, offset, (UINT)newval );
1601 default:
1602 WARN("Invalid offset %d\n", offset );
1603 return 0;
1608 /**********************************************************************
1609 * WIN_GetWindowLong
1611 * Helper function for GetWindowLong().
1613 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1615 LONG retvalue;
1616 WND * wndPtr = WIN_FindWndPtr( hwnd );
1617 if (!wndPtr) return 0;
1618 if (offset >= 0)
1620 if (offset + sizeof(LONG) > wndPtr->cbWndExtra)
1622 WARN("Invalid offset %d\n", offset );
1623 retvalue = 0;
1624 goto end;
1626 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1627 /* Special case for dialog window procedure */
1628 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1630 retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1631 goto end;
1633 goto end;
1635 switch(offset)
1637 case GWL_USERDATA: retvalue = wndPtr->userdata;
1638 goto end;
1639 case GWL_STYLE: retvalue = wndPtr->dwStyle;
1640 goto end;
1641 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle;
1642 goto end;
1643 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu;
1644 goto end;
1645 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc,
1646 type );
1647 goto end;
1648 case GWL_HWNDPARENT: retvalue = (LONG)GetParent(hwnd);
1649 goto end;
1650 case GWL_HINSTANCE: retvalue = wndPtr->hInstance;
1651 goto end;
1652 default:
1653 WARN("Unknown offset %d\n", offset );
1655 retvalue = 0;
1656 end:
1657 WIN_ReleaseWndPtr(wndPtr);
1658 return retvalue;
1662 /**********************************************************************
1663 * WIN_SetWindowLong
1665 * Helper function for SetWindowLong().
1667 * 0 is the failure code. However, in the case of failure SetLastError
1668 * must be set to distinguish between a 0 return value and a failure.
1670 * FIXME: The error values for SetLastError may not be right. Can
1671 * someone check with the real thing?
1673 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1674 WINDOWPROCTYPE type )
1676 LONG *ptr, retval;
1677 WND * wndPtr = WIN_FindWndPtr( hwnd );
1678 STYLESTRUCT style;
1680 TRACE("%x=%p %x %lx %x\n",hwnd, wndPtr, offset, newval, type);
1682 if (!wndPtr)
1684 /* Is this the right error? */
1685 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1686 return 0;
1689 if (offset >= 0)
1691 if (offset + sizeof(LONG) > wndPtr->cbWndExtra)
1693 WARN("Invalid offset %d\n", offset );
1695 /* Is this the right error? */
1696 SetLastError( ERROR_OUTOFMEMORY );
1698 retval = 0;
1699 goto end;
1701 ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1702 /* Special case for dialog window procedure */
1703 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1705 retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1706 WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
1707 type, WIN_PROC_WINDOW );
1708 goto end;
1711 else switch(offset)
1713 case GWL_ID:
1714 ptr = (DWORD*)&wndPtr->wIDmenu;
1715 break;
1716 case GWL_HINSTANCE:
1717 ptr = (DWORD*)&wndPtr->hInstance;
1718 break;
1719 case GWL_USERDATA:
1720 ptr = &wndPtr->userdata;
1721 break;
1722 case GWL_HWNDPARENT:
1723 retval = SetParent( hwnd, (HWND)newval );
1724 goto end;
1725 case GWL_WNDPROC:
1726 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
1727 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
1728 type, WIN_PROC_WINDOW );
1729 goto end;
1730 case GWL_STYLE:
1731 style.styleOld = wndPtr->dwStyle;
1732 style.styleNew = newval;
1733 SendMessageA(hwnd,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style);
1734 wndPtr->dwStyle = style.styleNew;
1735 SendMessageA(hwnd,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style);
1736 retval = style.styleOld;
1737 goto end;
1738 case GWL_EXSTYLE:
1739 style.styleOld = wndPtr->dwExStyle;
1740 style.styleNew = newval;
1741 SendMessageA(hwnd,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style);
1742 wndPtr->dwExStyle = style.styleNew;
1743 SendMessageA(hwnd,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style);
1744 retval = style.styleOld;
1745 goto end;
1747 default:
1748 WARN("Invalid offset %d\n", offset );
1750 /* Don't think this is right error but it should do */
1751 SetLastError( ERROR_OUTOFMEMORY );
1753 retval = 0;
1754 goto end;
1756 retval = *ptr;
1757 *ptr = newval;
1758 end:
1759 WIN_ReleaseWndPtr(wndPtr);
1760 return retval;
1764 /**********************************************************************
1765 * GetWindowLong (USER.135)
1767 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
1769 return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
1773 /**********************************************************************
1774 * GetWindowLongA (USER32.@)
1776 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
1778 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
1782 /**********************************************************************
1783 * GetWindowLongW (USER32.@)
1785 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
1787 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
1791 /**********************************************************************
1792 * SetWindowLong (USER.136)
1794 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
1796 return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
1800 /**********************************************************************
1801 * SetWindowLongA (USER32.@)
1803 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
1805 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
1809 /**********************************************************************
1810 * SetWindowLongW (USER32.@) Set window attribute
1812 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
1813 * value in a window's extra memory.
1815 * The _hwnd_ parameter specifies the window. is the handle to a
1816 * window that has extra memory. The _newval_ parameter contains the
1817 * new attribute or extra memory value. If positive, the _offset_
1818 * parameter is the byte-addressed location in the window's extra
1819 * memory to set. If negative, _offset_ specifies the window
1820 * attribute to set, and should be one of the following values:
1822 * GWL_EXSTYLE The window's extended window style
1824 * GWL_STYLE The window's window style.
1826 * GWL_WNDPROC Pointer to the window's window procedure.
1828 * GWL_HINSTANCE The window's pplication instance handle.
1830 * GWL_ID The window's identifier.
1832 * GWL_USERDATA The window's user-specified data.
1834 * If the window is a dialog box, the _offset_ parameter can be one of
1835 * the following values:
1837 * DWL_DLGPROC The address of the window's dialog box procedure.
1839 * DWL_MSGRESULT The return value of a message
1840 * that the dialog box procedure processed.
1842 * DWL_USER Application specific information.
1844 * RETURNS
1846 * If successful, returns the previous value located at _offset_. Otherwise,
1847 * returns 0.
1849 * NOTES
1851 * Extra memory for a window class is specified by a nonzero cbWndExtra
1852 * parameter of the WNDCLASS structure passed to RegisterClass() at the
1853 * time of class creation.
1855 * Using GWL_WNDPROC to set a new window procedure effectively creates
1856 * a window subclass. Use CallWindowProc() in the new windows procedure
1857 * to pass messages to the superclass's window procedure.
1859 * The user data is reserved for use by the application which created
1860 * the window.
1862 * Do not use GWL_STYLE to change the window's WS_DISABLE style;
1863 * instead, call the EnableWindow() function to change the window's
1864 * disabled state.
1866 * Do not use GWL_HWNDPARENT to reset the window's parent, use
1867 * SetParent() instead.
1869 * Win95:
1870 * When offset is GWL_STYLE and the calling app's ver is 4.0,
1871 * it sends WM_STYLECHANGING before changing the settings
1872 * and WM_STYLECHANGED afterwards.
1873 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
1875 * BUGS
1877 * GWL_STYLE does not dispatch WM_STYLE... messages.
1879 * CONFORMANCE
1881 * ECMA-234, Win32
1884 LONG WINAPI SetWindowLongW(
1885 HWND hwnd, /* [in] window to alter */
1886 INT offset, /* [in] offset, in bytes, of location to alter */
1887 LONG newval /* [in] new value of location */
1889 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
1893 /*******************************************************************
1894 * GetWindowTextA (USER32.@)
1896 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
1898 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount,
1899 (LPARAM)lpString );
1902 /*******************************************************************
1903 * InternalGetWindowText (USER32.@)
1905 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
1907 WND *win = WIN_FindWndPtr( hwnd );
1908 if (!win) return 0;
1909 if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
1910 else lpString[0] = 0;
1911 WIN_ReleaseWndPtr( win );
1912 return strlenW(lpString);
1916 /*******************************************************************
1917 * GetWindowTextW (USER32.@)
1919 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
1921 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount,
1922 (LPARAM)lpString );
1926 /*******************************************************************
1927 * SetWindowText (USER32.@)
1928 * SetWindowTextA (USER32.@)
1930 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
1932 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1936 /*******************************************************************
1937 * SetWindowTextW (USER32.@)
1939 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
1941 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1945 /*******************************************************************
1946 * GetWindowTextLengthA (USER32.@)
1948 INT WINAPI GetWindowTextLengthA( HWND hwnd )
1950 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1953 /*******************************************************************
1954 * GetWindowTextLengthW (USER32.@)
1956 INT WINAPI GetWindowTextLengthW( HWND hwnd )
1958 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1962 /*******************************************************************
1963 * IsWindow (USER32.@)
1965 BOOL WINAPI IsWindow( HWND hwnd )
1967 WND *ptr;
1968 BOOL ret;
1970 USER_Lock();
1971 if ((ptr = user_handles[LOWORD(hwnd)]))
1973 ret = ((ptr->dwMagic == WND_MAGIC) && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf));
1974 USER_Unlock();
1975 return ret;
1977 USER_Unlock();
1979 /* check other processes */
1980 SERVER_START_REQ( get_window_info )
1982 req->handle = hwnd;
1983 ret = !SERVER_CALL_ERR();
1985 SERVER_END_REQ;
1986 return ret;
1990 /***********************************************************************
1991 * GetWindowThreadProcessId (USER32.@)
1993 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
1995 WND *ptr;
1996 DWORD tid = 0;
1998 USER_Lock();
1999 if ((ptr = user_handles[LOWORD(hwnd)]))
2001 if ((ptr->dwMagic == WND_MAGIC) && (!HIWORD(hwnd) || hwnd == ptr->hwndSelf))
2003 /* got a valid window */
2004 tid = ptr->tid;
2005 if (process) *process = GetCurrentProcessId();
2007 else SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2008 USER_Unlock();
2009 return tid;
2011 USER_Unlock();
2013 /* check other processes */
2014 SERVER_START_REQ( get_window_info )
2016 req->handle = hwnd;
2017 if (!SERVER_CALL_ERR())
2019 tid = (DWORD)req->tid;
2020 if (process) *process = (DWORD)req->pid;
2023 SERVER_END_REQ;
2024 return tid;
2028 /*****************************************************************
2029 * GetParent (USER32.@)
2031 HWND WINAPI GetParent( HWND hwnd )
2033 WND *wndPtr;
2034 HWND retvalue = 0;
2036 if ((wndPtr = WIN_FindWndPtr(hwnd)))
2038 if (wndPtr->dwStyle & WS_CHILD)
2039 retvalue = wndPtr->parent->hwndSelf;
2040 else if (wndPtr->dwStyle & WS_POPUP)
2041 retvalue = wndPtr->owner;
2042 WIN_ReleaseWndPtr(wndPtr);
2044 return retvalue;
2048 /*****************************************************************
2049 * GetAncestor (USER32.@)
2051 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2053 HWND ret = 0;
2054 WND *wndPtr;
2056 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2057 if (wndPtr->hwndSelf == GetDesktopWindow()) goto done;
2059 switch(type)
2061 case GA_PARENT:
2062 WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2063 break;
2064 case GA_ROOT:
2065 while (wndPtr->parent->hwndSelf != GetDesktopWindow())
2066 WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2067 break;
2068 case GA_ROOTOWNER:
2069 while (wndPtr->parent->hwndSelf != GetDesktopWindow())
2070 WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2071 while (wndPtr && wndPtr->owner)
2073 WND *ptr = WIN_FindWndPtr( wndPtr->owner );
2074 WIN_ReleaseWndPtr( wndPtr );
2075 wndPtr = ptr;
2077 break;
2079 ret = wndPtr ? wndPtr->hwndSelf : 0;
2080 done:
2081 WIN_ReleaseWndPtr( wndPtr );
2082 return ret;
2086 /*****************************************************************
2087 * SetParent (USER32.@)
2089 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2091 WND *wndPtr;
2092 DWORD dwStyle;
2093 HWND retvalue;
2095 if (!parent) parent = GetDesktopWindow();
2096 else parent = WIN_GetFullHandle( parent );
2098 /* sanity checks */
2099 if (WIN_GetFullHandle(hwnd) == GetDesktopWindow() || !IsWindow( parent ))
2101 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2102 return 0;
2105 if (USER_Driver.pSetParent)
2106 return USER_Driver.pSetParent( hwnd, parent );
2108 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2110 dwStyle = wndPtr->dwStyle;
2112 /* Windows hides the window first, then shows it again
2113 * including the WM_SHOWWINDOW messages and all */
2114 if (dwStyle & WS_VISIBLE) ShowWindow( hwnd, SW_HIDE );
2116 retvalue = wndPtr->parent->hwndSelf; /* old parent */
2117 if (parent != retvalue)
2119 WIN_LinkWindow( hwnd, parent, HWND_TOP );
2121 if (parent != GetDesktopWindow()) /* a child window */
2123 if (!(dwStyle & WS_CHILD))
2125 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2126 if (menu) DestroyMenu( menu );
2130 WIN_ReleaseWndPtr( wndPtr );
2132 /* SetParent additionally needs to make hwnd the topmost window
2133 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2134 WM_WINDOWPOSCHANGED notification messages.
2136 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2137 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|
2138 ((dwStyle & WS_VISIBLE)?SWP_SHOWWINDOW:0));
2139 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2140 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2141 return retvalue;
2145 /*******************************************************************
2146 * IsChild (USER32.@)
2148 BOOL WINAPI IsChild( HWND parent, HWND child )
2150 HWND *list = WIN_ListParents( child );
2151 int i;
2152 BOOL ret;
2154 if (!list) return FALSE;
2155 parent = WIN_GetFullHandle( parent );
2156 for (i = 0; list[i]; i++) if (list[i] == parent) break;
2157 ret = (list[i] != 0);
2158 HeapFree( GetProcessHeap(), 0, list );
2159 return ret;
2163 /***********************************************************************
2164 * IsWindowVisible (USER32.@)
2166 BOOL WINAPI IsWindowVisible( HWND hwnd )
2168 HWND *list;
2169 BOOL retval;
2170 int i;
2172 if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2173 if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2174 for (i = 0; list[i]; i++)
2175 if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2176 retval = !list[i];
2177 HeapFree( GetProcessHeap(), 0, list );
2178 return retval;
2182 /***********************************************************************
2183 * WIN_IsWindowDrawable
2185 * hwnd is drawable when it is visible, all parents are not
2186 * minimized, and it is itself not minimized unless we are
2187 * trying to draw its default class icon.
2189 BOOL WIN_IsWindowDrawable( WND* wnd, BOOL icon )
2191 HWND *list;
2192 BOOL retval;
2193 int i;
2195 if (!(wnd->dwStyle & WS_VISIBLE)) return FALSE;
2196 if ((wnd->dwStyle & WS_MINIMIZE) &&
2197 icon && GetClassLongA( wnd->hwndSelf, GCL_HICON )) return FALSE;
2199 if (!(list = WIN_ListParents( wnd->hwndSelf ))) return TRUE;
2200 for (i = 0; list[i]; i++)
2201 if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2202 break;
2203 retval = !list[i];
2204 HeapFree( GetProcessHeap(), 0, list );
2205 return retval;
2209 /*******************************************************************
2210 * GetTopWindow (USER32.@)
2212 HWND WINAPI GetTopWindow( HWND hwnd )
2214 if (!hwnd) hwnd = GetDesktopWindow();
2215 return GetWindow( hwnd, GW_CHILD );
2219 /*******************************************************************
2220 * GetWindow (USER32.@)
2222 HWND WINAPI GetWindow( HWND hwnd, WORD rel )
2224 HWND retval;
2226 WND * wndPtr = WIN_FindWndPtr( hwnd );
2227 if (!wndPtr) return 0;
2228 hwnd = wndPtr->hwndSelf; /* make it a full handle */
2230 switch(rel)
2232 case GW_HWNDFIRST:
2233 retval = wndPtr->parent ? wndPtr->parent->child->hwndSelf : 0;
2234 goto end;
2236 case GW_HWNDLAST:
2237 if (!wndPtr->parent)
2239 retval = 0; /* Desktop window */
2240 goto end;
2242 while (wndPtr->next)
2244 WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
2246 retval = wndPtr->hwndSelf;
2247 goto end;
2249 case GW_HWNDNEXT:
2250 retval = wndPtr->next ? wndPtr->next->hwndSelf : 0;
2251 goto end;
2253 case GW_HWNDPREV:
2254 if (!wndPtr->parent)
2256 retval = 0; /* Desktop window */
2257 goto end;
2259 WIN_UpdateWndPtr(&wndPtr,wndPtr->parent->child); /* First sibling */
2260 if (wndPtr->hwndSelf == hwnd)
2262 retval = 0; /* First in list */
2263 goto end;
2265 while (wndPtr->next)
2267 if (wndPtr->next->hwndSelf == hwnd)
2269 retval = wndPtr->hwndSelf;
2270 goto end;
2272 WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
2274 retval = 0;
2275 goto end;
2277 case GW_OWNER:
2278 retval = wndPtr->owner;
2279 goto end;
2281 case GW_CHILD:
2282 retval = wndPtr->child ? wndPtr->child->hwndSelf : 0;
2283 goto end;
2285 retval = 0;
2286 end:
2287 WIN_ReleaseWndPtr(wndPtr);
2288 return retval;
2292 /***********************************************************************
2293 * WIN_InternalShowOwnedPopups
2295 * Internal version of ShowOwnedPopups; Wine functions should use this
2296 * to avoid interfering with application calls to ShowOwnedPopups
2297 * and to make sure the application can't prevent showing/hiding.
2299 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2303 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2305 int count = 0;
2306 WND *pWnd;
2307 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2309 if (!win_array) return TRUE;
2312 * Show windows Lowest first, Highest last to preserve Z-Order
2314 while (win_array[count]) count++;
2315 while (--count >= 0)
2317 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2318 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2320 if (pWnd->dwStyle & WS_POPUP)
2322 if (fShow)
2324 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2325 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2328 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2330 ShowWindow(pWnd->hwndSelf,SW_SHOW);
2331 pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2334 else
2336 if ( IsWindowVisible(pWnd->hwndSelf) && /* hide only if window is visible */
2337 !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2338 !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2341 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2343 ShowWindow(pWnd->hwndSelf,SW_HIDE);
2344 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2345 pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2349 WIN_ReleaseWndPtr( pWnd );
2351 HeapFree( GetProcessHeap(), 0, win_array );
2353 return TRUE;
2356 /*******************************************************************
2357 * ShowOwnedPopups (USER32.@)
2359 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2361 int count = 0;
2362 WND *pWnd;
2363 HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2365 if (!win_array) return TRUE;
2367 while (win_array[count]) count++;
2368 while (--count >= 0)
2370 if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2371 if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2373 if (pWnd->dwStyle & WS_POPUP)
2375 if (fShow)
2377 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2379 /* In Windows, ShowOwnedPopups(TRUE) generates
2380 * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2381 * regardless of the state of the owner
2383 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2384 pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2387 else
2389 if (IsWindowVisible(pWnd->hwndSelf))
2391 /* In Windows, ShowOwnedPopups(FALSE) generates
2392 * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2393 * regardless of the state of the owner
2395 SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2396 pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2400 WIN_ReleaseWndPtr( pWnd );
2402 HeapFree( GetProcessHeap(), 0, win_array );
2403 return TRUE;
2407 /*******************************************************************
2408 * GetLastActivePopup (USER32.@)
2410 HWND WINAPI GetLastActivePopup( HWND hwnd )
2412 HWND retval;
2413 WND *wndPtr =WIN_FindWndPtr(hwnd);
2414 if (!wndPtr) return hwnd;
2415 retval = wndPtr->hwndLastActive;
2416 if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2417 WIN_ReleaseWndPtr(wndPtr);
2418 return retval;
2422 /*******************************************************************
2423 * WIN_ListParents
2425 * Build an array of all parents of a given window, starting with
2426 * the immediate parent. The array must be freed with HeapFree.
2427 * Returns NULL if window is a top-level window.
2429 HWND *WIN_ListParents( HWND hwnd )
2431 WND *parent, *wndPtr = WIN_FindWndPtr( hwnd );
2432 HWND *list = NULL;
2433 UINT i, count = 0;
2435 /* First count the windows */
2437 if (!wndPtr) return NULL;
2439 parent = wndPtr->parent;
2440 while (parent && parent->hwndSelf != GetDesktopWindow())
2442 count++;
2443 parent = parent->parent;
2446 if (count)
2448 if ((list = HeapAlloc( GetProcessHeap(), 0, sizeof(HWND) * (count + 1) )))
2450 parent = wndPtr->parent;
2451 for (i = 0; i < count; i++)
2453 list[i] = parent->hwndSelf;
2454 parent = parent->parent;
2456 list[i] = 0;
2460 WIN_ReleaseWndPtr( wndPtr );
2461 return list;
2465 /*******************************************************************
2466 * WIN_ListChildren
2468 * Build an array of the children of a given window. The array must be
2469 * freed with HeapFree. Returns NULL when no windows are found.
2471 HWND *WIN_ListChildren( HWND hwnd )
2473 WND *pWnd, *wndPtr = WIN_FindWndPtr( hwnd );
2474 HWND *list, *phwnd;
2475 UINT count = 0;
2477 /* First count the windows */
2479 if (!wndPtr) return NULL;
2481 pWnd = WIN_LockWndPtr(wndPtr->child);
2482 while (pWnd)
2484 count++;
2485 WIN_UpdateWndPtr(&pWnd,pWnd->next);
2488 if( count )
2490 /* Now build the list of all windows */
2492 if ((list = HeapAlloc( GetProcessHeap(), 0, sizeof(HWND) * (count + 1))))
2494 for (pWnd = WIN_LockWndPtr(wndPtr->child), phwnd = list, count = 0; pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2496 *phwnd++ = pWnd->hwndSelf;
2497 count++;
2499 WIN_ReleaseWndPtr(pWnd);
2500 *phwnd = 0;
2502 else count = 0;
2503 } else list = NULL;
2505 WIN_ReleaseWndPtr( wndPtr );
2506 return list;
2510 /*******************************************************************
2511 * EnumWindows (USER32.@)
2513 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2515 HWND *list;
2516 BOOL ret = TRUE;
2517 int i, iWndsLocks;
2519 /* We have to build a list of all windows first, to avoid */
2520 /* unpleasant side-effects, for instance if the callback */
2521 /* function changes the Z-order of the windows. */
2523 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE;
2525 /* Now call the callback function for every window */
2527 iWndsLocks = WIN_SuspendWndsLock();
2528 for (i = 0; list[i]; i++)
2530 /* Make sure that the window still exists */
2531 if (!IsWindow( list[i] )) continue;
2532 if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2534 WIN_RestoreWndsLock(iWndsLocks);
2535 HeapFree( GetProcessHeap(), 0, list );
2536 return ret;
2540 /**********************************************************************
2541 * EnumTaskWindows16 (USER.225)
2543 BOOL16 WINAPI EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
2544 LPARAM lParam )
2546 TDB *tdb = TASK_GetPtr( hTask );
2547 if (!tdb) return FALSE;
2548 return EnumThreadWindows( (DWORD)tdb->teb->tid, (WNDENUMPROC)func, lParam );
2552 /**********************************************************************
2553 * EnumThreadWindows (USER32.@)
2555 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2557 HWND *list;
2558 int i, iWndsLocks;
2560 if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE;
2562 /* Now call the callback function for every window */
2564 iWndsLocks = WIN_SuspendWndsLock();
2565 for (i = 0; list[i]; i++)
2567 if (GetWindowThreadProcessId( list[i], NULL ) != id) continue;
2568 if (!func( list[i], lParam )) break;
2570 WIN_RestoreWndsLock(iWndsLocks);
2571 HeapFree( GetProcessHeap(), 0, list );
2572 return TRUE;
2576 /**********************************************************************
2577 * WIN_EnumChildWindows
2579 * Helper function for EnumChildWindows().
2581 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2583 HWND *childList;
2584 BOOL ret = FALSE;
2586 for ( ; *list; list++)
2588 /* Make sure that the window still exists */
2589 if (!IsWindow( *list )) continue;
2590 /* skip owned windows */
2591 if (GetWindow( *list, GW_OWNER )) continue;
2592 /* Build children list first */
2593 childList = WIN_ListChildren( *list );
2595 ret = func( *list, lParam );
2597 if (childList)
2599 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2600 HeapFree( GetProcessHeap(), 0, childList );
2602 if (!ret) return FALSE;
2604 return TRUE;
2608 /**********************************************************************
2609 * EnumChildWindows (USER32.@)
2611 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2613 HWND *list;
2614 int iWndsLocks;
2616 if (!(list = WIN_ListChildren( parent ))) return FALSE;
2617 iWndsLocks = WIN_SuspendWndsLock();
2618 WIN_EnumChildWindows( list, func, lParam );
2619 WIN_RestoreWndsLock(iWndsLocks);
2620 HeapFree( GetProcessHeap(), 0, list );
2621 return TRUE;
2625 /*******************************************************************
2626 * AnyPopup (USER.52)
2628 BOOL16 WINAPI AnyPopup16(void)
2630 return AnyPopup();
2634 /*******************************************************************
2635 * AnyPopup (USER32.@)
2637 BOOL WINAPI AnyPopup(void)
2639 int i;
2640 BOOL retvalue;
2641 HWND *list = WIN_ListChildren( GetDesktopWindow() );
2643 if (!list) return FALSE;
2644 for (i = 0; list[i]; i++)
2646 if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2648 retvalue = (list[i] != 0);
2649 HeapFree( GetProcessHeap(), 0, list );
2650 return retvalue;
2654 /*******************************************************************
2655 * FlashWindow (USER32.@)
2657 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2659 WND *wndPtr = WIN_FindWndPtr(hWnd);
2661 TRACE("%04x\n", hWnd);
2663 if (!wndPtr) return FALSE;
2664 hWnd = wndPtr->hwndSelf; /* make it a full handle */
2666 if (wndPtr->dwStyle & WS_MINIMIZE)
2668 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2670 HDC hDC = GetDC(hWnd);
2672 if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
2673 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
2675 ReleaseDC( hWnd, hDC );
2676 wndPtr->flags |= WIN_NCACTIVATED;
2678 else
2680 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2681 wndPtr->flags &= ~WIN_NCACTIVATED;
2683 WIN_ReleaseWndPtr(wndPtr);
2684 return TRUE;
2686 else
2688 WPARAM16 wparam;
2689 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2690 else wparam = (hWnd == GetActiveWindow());
2692 WIN_ReleaseWndPtr(wndPtr);
2693 SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2694 return wparam;
2699 /*******************************************************************
2700 * GetWindowContextHelpId (USER32.@)
2702 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
2704 DWORD retval;
2705 WND *wnd = WIN_FindWndPtr( hwnd );
2706 if (!wnd) return 0;
2707 retval = wnd->helpContext;
2708 WIN_ReleaseWndPtr(wnd);
2709 return retval;
2713 /*******************************************************************
2714 * SetWindowContextHelpId (USER32.@)
2716 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
2718 WND *wnd = WIN_FindWndPtr( hwnd );
2719 if (!wnd) return FALSE;
2720 wnd->helpContext = id;
2721 WIN_ReleaseWndPtr(wnd);
2722 return TRUE;
2726 /*******************************************************************
2727 * DRAG_QueryUpdate
2729 * recursively find a child that contains spDragInfo->pt point
2730 * and send WM_QUERYDROPOBJECT
2732 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
2734 BOOL16 wParam, bResult = 0;
2735 POINT pt;
2736 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
2737 RECT tempRect;
2739 if (!ptrDragInfo) return FALSE;
2741 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
2743 GetWindowRect(hQueryWnd,&tempRect);
2745 if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
2747 if (!IsIconic( hQueryWnd ))
2749 GetClientRect( hQueryWnd, &tempRect );
2750 MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
2752 if (PtInRect( &tempRect, pt))
2754 int i;
2755 HWND *list = WIN_ListChildren( hQueryWnd );
2757 wParam = 0;
2759 if (list)
2761 for (i = 0; list[i]; i++)
2763 if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
2765 GetWindowRect( list[i], &tempRect );
2766 if (PtInRect( &tempRect, pt )) break;
2769 if (list[i])
2771 if (IsWindowEnabled( list[i] ))
2772 bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
2774 HeapFree( GetProcessHeap(), 0, list );
2776 if(bResult) return bResult;
2778 else wParam = 1;
2780 else wParam = 1;
2782 ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
2784 ptrDragInfo->hScope = hQueryWnd;
2786 if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
2787 else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
2789 if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
2791 return bResult;
2795 /*******************************************************************
2796 * DragDetect (USER32.@)
2798 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
2800 MSG msg;
2801 RECT rect;
2803 rect.left = pt.x - wDragWidth;
2804 rect.right = pt.x + wDragWidth;
2806 rect.top = pt.y - wDragHeight;
2807 rect.bottom = pt.y + wDragHeight;
2809 SetCapture(hWnd);
2811 while(1)
2813 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
2815 if( msg.message == WM_LBUTTONUP )
2817 ReleaseCapture();
2818 return 0;
2820 if( msg.message == WM_MOUSEMOVE )
2822 POINT tmp;
2823 tmp.x = LOWORD(msg.lParam);
2824 tmp.y = HIWORD(msg.lParam);
2825 if( !PtInRect( &rect, tmp ))
2827 ReleaseCapture();
2828 return 1;
2832 WaitMessage();
2834 return 0;
2837 /******************************************************************************
2838 * DragObject (USER.464)
2840 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
2841 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
2843 MSG msg;
2844 LPDRAGINFO16 lpDragInfo;
2845 SEGPTR spDragInfo;
2846 HCURSOR16 hDragCursor=0, hOldCursor=0, hBummer=0;
2847 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
2848 HCURSOR16 hCurrentCursor = 0;
2849 HWND16 hCurrentWnd = 0;
2851 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
2852 spDragInfo = K32WOWGlobalLock16(hDragInfo);
2854 if( !lpDragInfo || !spDragInfo ) return 0L;
2856 if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
2858 GlobalFree16(hDragInfo);
2859 return 0L;
2862 if(hCursor)
2864 if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
2866 GlobalFree16(hDragInfo);
2867 return 0L;
2870 if( hDragCursor == hCursor ) hDragCursor = 0;
2871 else hCursor = hDragCursor;
2873 hOldCursor = SetCursor(hDragCursor);
2876 lpDragInfo->hWnd = hWnd;
2877 lpDragInfo->hScope = 0;
2878 lpDragInfo->wFlags = wObj;
2879 lpDragInfo->hList = szList; /* near pointer! */
2880 lpDragInfo->hOfStruct = hOfStruct;
2881 lpDragInfo->l = 0L;
2883 SetCapture(hWnd);
2884 ShowCursor( TRUE );
2888 GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
2890 *(lpDragInfo+1) = *lpDragInfo;
2892 lpDragInfo->pt.x = msg.pt.x;
2893 lpDragInfo->pt.y = msg.pt.y;
2895 /* update DRAGINFO struct */
2896 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
2898 if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
2899 hCurrentCursor = hCursor;
2900 else
2902 hCurrentCursor = hBummer;
2903 lpDragInfo->hScope = 0;
2905 if( hCurrentCursor )
2906 SetCursor(hCurrentCursor);
2908 /* send WM_DRAGLOOP */
2909 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
2910 (LPARAM) spDragInfo );
2911 /* send WM_DRAGSELECT or WM_DRAGMOVE */
2912 if( hCurrentWnd != lpDragInfo->hScope )
2914 if( hCurrentWnd )
2915 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
2916 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
2917 HIWORD(spDragInfo)) );
2918 hCurrentWnd = lpDragInfo->hScope;
2919 if( hCurrentWnd )
2920 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
2922 else
2923 if( hCurrentWnd )
2924 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
2926 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
2928 ReleaseCapture();
2929 ShowCursor( FALSE );
2931 if( hCursor )
2933 SetCursor( hOldCursor );
2934 if (hDragCursor) DestroyCursor( hDragCursor );
2937 if( hCurrentCursor != hBummer )
2938 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
2939 (WPARAM16)hWnd, (LPARAM)spDragInfo );
2940 else
2941 msg.lParam = 0;
2942 GlobalFree16(hDragInfo);
2944 return (DWORD)(msg.lParam);
2948 /******************************************************************************
2949 * GetWindowModuleFileNameA (USER32.@)
2951 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
2953 FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
2954 hwnd, lpszFileName, cchFileNameMax);
2955 return 0;
2958 /******************************************************************************
2959 * GetWindowModuleFileNameW (USER32.@)
2961 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
2963 FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
2964 hwnd, lpszFileName, cchFileNameMax);
2965 return 0;