2 * Window related functions
4 * Copyright 1993, 1994 Alexandre Julliard
10 #include "wine/winbase16.h"
11 #include "wine/winuser16.h"
12 #include "wine/unicode.h"
19 #include "cursoricon.h"
27 #include "stackframe.h"
28 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(win);
31 DECLARE_DEBUG_CHANNEL(msg);
33 /**********************************************************************/
35 WND_DRIVER *WND_Driver = NULL;
38 static WND *pWndDesktop = NULL;
40 static HWND hwndSysModal = 0;
42 static WORD wDragWidth = 4;
43 static WORD wDragHeight= 3;
46 static SYSLEVEL WIN_SysLevel = { CRITICAL_SECTION_INIT, 2 };
48 /***********************************************************************
51 * Locks access to all WND structures for thread safeness
53 void WIN_LockWnds( void )
55 _EnterSysLevel( &WIN_SysLevel );
58 /***********************************************************************
61 * Unlocks access to all WND structures
63 void WIN_UnlockWnds( void )
65 _LeaveSysLevel( &WIN_SysLevel );
68 /***********************************************************************
71 * Suspend the lock on WND structures.
72 * Returns the number of locks suspended
74 int WIN_SuspendWndsLock( void )
76 int isuspendedLocks = _ConfirmSysLevel( &WIN_SysLevel );
77 int count = isuspendedLocks;
80 _LeaveSysLevel( &WIN_SysLevel );
82 return isuspendedLocks;
85 /***********************************************************************
88 * Restore the suspended locks on WND structures
90 void WIN_RestoreWndsLock( int ipreviousLocks )
92 while ( ipreviousLocks-- > 0 )
93 _EnterSysLevel( &WIN_SysLevel );
96 /***********************************************************************
99 * Return a pointer to the WND structure corresponding to a HWND.
101 WND * WIN_FindWndPtr( HWND hwnd )
105 if (!hwnd || HIWORD(hwnd)) goto error2;
106 ptr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
107 /* Lock all WND structures for thread safeness*/
109 /*and increment destruction monitoring*/
112 if (ptr->dwMagic != WND_MAGIC) goto error;
113 if (ptr->hwndSelf != hwnd)
115 ERR("Can't happen: hwnd %04x self pointer is %04x\n",hwnd, ptr->hwndSelf );
118 /* returns a locked pointer */
121 /* Unlock all WND structures for thread safeness*/
123 /* and decrement destruction monitoring value */
128 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
132 /***********************************************************************
135 * Use in case the wnd ptr is not initialized with WIN_FindWndPtr
137 * Returns the locked initialisation pointer
139 WND *WIN_LockWndPtr(WND *initWndPtr)
141 if(!initWndPtr) return 0;
143 /* Lock all WND structures for thread safeness*/
145 /*and increment destruction monitoring*/
146 initWndPtr->irefCount++;
152 /***********************************************************************
155 * Release the pointer to the WND structure.
157 void WIN_ReleaseWndPtr(WND *wndPtr)
161 /*Decrement destruction monitoring value*/
163 /* Check if it's time to release the memory*/
164 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
167 USER_HEAP_FREE( wndPtr->hwndSelf);
168 wndPtr->hwndSelf = 0;
170 else if(wndPtr->irefCount < 0)
172 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
173 ERR("forgot a Lock on %p somewhere\n",wndPtr);
175 /*unlock all WND structures for thread safeness*/
179 /***********************************************************************
182 * Updates the value of oldPtr to newPtr.
184 void WIN_UpdateWndPtr(WND **oldPtr, WND *newPtr)
188 tmpWnd = WIN_LockWndPtr(newPtr);
189 WIN_ReleaseWndPtr(*oldPtr);
194 /***********************************************************************
197 * Dump the content of a window structure to stderr.
199 void WIN_DumpWindow( HWND hwnd )
205 if (!(ptr = WIN_FindWndPtr( hwnd )))
207 WARN("%04x is not a window handle\n", hwnd );
211 if (!GetClassNameA( hwnd, className, sizeof(className ) ))
212 strcpy( className, "#NULL#" );
214 TRACE("Window %04x (%p):\n", hwnd, ptr );
215 DPRINTF( "next=%p child=%p parent=%p owner=%p class=%p '%s'\n"
216 "inst=%04x taskQ=%04x updRgn=%04x active=%04x dce=%p idmenu=%08x\n"
217 "style=%08lx exstyle=%08lx wndproc=%08x text='%s'\n"
218 "client=%d,%d-%d,%d window=%d,%d-%d,%d"
219 "sysmenu=%04x flags=%04x props=%p vscroll=%p hscroll=%p\n",
220 ptr->next, ptr->child, ptr->parent, ptr->owner,
221 ptr->class, className, ptr->hInstance, ptr->hmemTaskQ,
222 ptr->hrgnUpdate, ptr->hwndLastActive, ptr->dce, ptr->wIDmenu,
223 ptr->dwStyle, ptr->dwExStyle, (UINT)ptr->winproc,
224 ptr->text ? debugstr_w(ptr->text) : "",
225 ptr->rectClient.left, ptr->rectClient.top, ptr->rectClient.right,
226 ptr->rectClient.bottom, ptr->rectWindow.left, ptr->rectWindow.top,
227 ptr->rectWindow.right, ptr->rectWindow.bottom, ptr->hSysMenu,
228 ptr->flags, ptr->pProp, ptr->pVScroll, ptr->pHScroll );
232 DPRINTF( "extra bytes:" );
233 for (i = 0; i < ptr->cbWndExtra; i++)
234 DPRINTF( " %02x", *((BYTE*)ptr->wExtra+i) );
238 WIN_ReleaseWndPtr(ptr);
242 /***********************************************************************
245 * Walk the windows tree and print each window on stderr.
247 void WIN_WalkWindows( HWND hwnd, int indent )
252 ptr = hwnd ? WIN_FindWndPtr( hwnd ) : WIN_GetDesktop();
256 WARN("Invalid window handle %04x\n", hwnd );
260 if (!indent) /* first time around */
261 DPRINTF( "%-16.16s %-8.8s %-6.6s %-17.17s %-8.8s %s\n",
262 "hwnd", " wndPtr", "queue", "Class Name", " Style", " WndProc"
267 DPRINTF( "%*s%04x%*s", indent, "", ptr->hwndSelf, 13-indent,"");
269 GetClassNameA( hwnd, className, sizeof(className) );
270 DPRINTF( "%08lx %-6.4x %-17.17s %08x %08x %.14s\n",
271 (DWORD)ptr, ptr->hmemTaskQ, className,
272 (UINT)ptr->dwStyle, (UINT)ptr->winproc,
273 ptr->text ? debugstr_w(ptr->text) : "<null>");
275 if (ptr->child) WIN_WalkWindows( ptr->child->hwndSelf, indent+1 );
276 WIN_UpdateWndPtr(&ptr,ptr->next);
282 /***********************************************************************
285 * Remove a window from the siblings linked list.
287 BOOL WIN_UnlinkWindow( HWND hwnd )
289 WND *wndPtr, **ppWnd;
292 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
293 else if(!wndPtr->parent)
295 WIN_ReleaseWndPtr(wndPtr);
299 ppWnd = &wndPtr->parent->child;
300 while (*ppWnd && *ppWnd != wndPtr) ppWnd = &(*ppWnd)->next;
303 *ppWnd = wndPtr->next;
306 WIN_ReleaseWndPtr(wndPtr);
311 /***********************************************************************
314 * Insert a window into the siblings linked list.
315 * The window is inserted after the specified window, which can also
316 * be specified as HWND_TOP or HWND_BOTTOM.
318 BOOL WIN_LinkWindow( HWND hwnd, HWND hwndInsertAfter )
320 WND *wndPtr, **ppWnd;
322 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
323 else if(!wndPtr->parent)
325 WIN_ReleaseWndPtr(wndPtr);
328 if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM))
330 ppWnd = &wndPtr->parent->child; /* Point to first sibling hwnd */
331 if (hwndInsertAfter == HWND_BOTTOM) /* Find last sibling hwnd */
332 while (*ppWnd) ppWnd = &(*ppWnd)->next;
334 else /* Normal case */
336 WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter );
339 WIN_ReleaseWndPtr(wndPtr);
342 ppWnd = &afterPtr->next;
343 WIN_ReleaseWndPtr(afterPtr);
345 wndPtr->next = *ppWnd;
347 WIN_ReleaseWndPtr(wndPtr);
352 /***********************************************************************
353 * WIN_FindWinToRepaint
355 * Find a window that needs repaint.
357 HWND WIN_FindWinToRepaint( HWND hwnd, HQUEUE16 hQueue )
362 /* Note: the desktop window never gets WM_PAINT messages
363 * The real reason why is because Windows DesktopWndProc
364 * does ValidateRgn inside WM_ERASEBKGND handler.
367 pWnd = hwnd ? WIN_FindWndPtr(hwnd) : WIN_LockWndPtr(pWndDesktop->child);
369 for ( ; pWnd ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
371 if (!(pWnd->dwStyle & WS_VISIBLE))
373 TRACE("skipping window %04x\n",
376 else if ((pWnd->hmemTaskQ == hQueue) &&
377 (pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT)))
380 else if (pWnd->child )
381 if ((hwndRet = WIN_FindWinToRepaint( pWnd->child->hwndSelf, hQueue )) )
383 WIN_ReleaseWndPtr(pWnd);
394 hwndRet = pWnd->hwndSelf;
396 /* look among siblings if we got a transparent window */
397 while (pWnd && ((pWnd->dwExStyle & WS_EX_TRANSPARENT) ||
398 !(pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT))))
400 WIN_UpdateWndPtr(&pWnd,pWnd->next);
404 hwndRet = pWnd->hwndSelf;
405 WIN_ReleaseWndPtr(pWnd);
407 TRACE("found %04x\n",hwndRet);
412 /***********************************************************************
415 * Destroy storage associated to a window. "Internals" p.358
416 * returns a locked wndPtr->next
418 static WND* WIN_DestroyWindow( WND* wndPtr )
420 HWND hwnd = wndPtr->hwndSelf;
423 TRACE("%04x\n", wndPtr->hwndSelf );
425 /* free child windows */
426 WIN_LockWndPtr(wndPtr->child);
427 while ((pWnd = wndPtr->child))
429 wndPtr->child = WIN_DestroyWindow( pWnd );
430 WIN_ReleaseWndPtr(pWnd);
434 * Clear the update region to make sure no WM_PAINT messages will be
435 * generated for this window while processing the WM_NCDESTROY.
437 if ((wndPtr->hrgnUpdate) || (wndPtr->flags & WIN_INTERNAL_PAINT))
439 if (wndPtr->hrgnUpdate > 1)
440 DeleteObject( wndPtr->hrgnUpdate );
442 QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
444 wndPtr->hrgnUpdate = 0;
448 * Send the WM_NCDESTROY to the window being destroyed.
450 SendMessageA( wndPtr->hwndSelf, WM_NCDESTROY, 0, 0);
452 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
454 WINPOS_CheckInternalPos( wndPtr );
455 if( hwnd == GetCapture()) ReleaseCapture();
457 /* free resources associated with the window */
459 TIMER_RemoveWindowTimers( wndPtr->hwndSelf );
460 PROPERTY_RemoveWindowProps( wndPtr );
462 wndPtr->dwMagic = 0; /* Mark it as invalid */
464 /* toss stale messages from the queue */
466 if( wndPtr->hmemTaskQ )
468 BOOL bPostQuit = FALSE;
469 WPARAM wQuitParam = 0;
470 MESSAGEQUEUE* msgQ = (MESSAGEQUEUE*) QUEUE_Lock(wndPtr->hmemTaskQ);
473 while( (qmsg = QUEUE_FindMsg(msgQ, hwnd, 0, 0)) != 0 )
475 if( qmsg->msg.message == WM_QUIT )
478 wQuitParam = qmsg->msg.wParam;
480 QUEUE_RemoveMsg(msgQ, qmsg);
485 /* repost WM_QUIT to make sure this app exits its message loop */
486 if( bPostQuit ) PostQuitMessage(wQuitParam);
487 wndPtr->hmemTaskQ = 0;
490 if (!(wndPtr->dwStyle & WS_CHILD))
493 DestroyMenu( wndPtr->wIDmenu );
496 if (wndPtr->hSysMenu)
498 DestroyMenu( wndPtr->hSysMenu );
499 wndPtr->hSysMenu = 0;
501 wndPtr->pDriver->pDestroyWindow( wndPtr );
502 DCE_FreeWindowDCE( wndPtr ); /* Always do this to catch orphaned DCs */
503 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
504 CLASS_RemoveWindow( wndPtr->class );
505 wndPtr->class = NULL;
507 WIN_UpdateWndPtr(&pWnd,wndPtr->next);
509 wndPtr->pDriver->pFinalize(wndPtr);
514 /***********************************************************************
515 * WIN_ResetQueueWindows
517 * Reset the queue of all the children of a given window.
518 * Return TRUE if something was done.
520 BOOL WIN_ResetQueueWindows( WND* wnd, HQUEUE16 hQueue, HQUEUE16 hNew )
524 if (hNew) /* Set a new queue */
526 for (wnd = WIN_LockWndPtr(wnd->child); (wnd);WIN_UpdateWndPtr(&wnd,wnd->next))
528 if (wnd->hmemTaskQ == hQueue)
530 wnd->hmemTaskQ = hNew;
535 ret |= WIN_ResetQueueWindows( wnd, hQueue, hNew );
539 else /* Queue is being destroyed */
543 WND *tmp = WIN_LockWndPtr(wnd->child);
548 if (tmp->hmemTaskQ == hQueue)
550 DestroyWindow( tmp->hwndSelf );
554 tmp2 = WIN_LockWndPtr(tmp->child);
555 if (tmp2 && WIN_ResetQueueWindows(tmp2,hQueue,0))
559 WIN_UpdateWndPtr(&tmp,tmp->next);
561 WIN_ReleaseWndPtr(tmp2);
563 WIN_ReleaseWndPtr(tmp);
570 /***********************************************************************
571 * WIN_CreateDesktopWindow
573 * Create the desktop window.
575 BOOL WIN_CreateDesktopWindow(void)
577 struct tagCLASS *class;
584 TRACE("Creating desktop window\n");
587 if (!WINPOS_CreateInternalPosAtom() ||
588 !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
589 &wndExtra, &winproc, &clsStyle, &dce )))
592 hwndDesktop = USER_HEAP_ALLOC( sizeof(WND) + wndExtra );
593 if (!hwndDesktop) return FALSE;
594 pWndDesktop = (WND *) USER_HEAP_LIN_ADDR( hwndDesktop );
596 pWndDesktop->pDriver = WND_Driver;
597 pWndDesktop->pDriver->pInitialize(pWndDesktop);
599 pWndDesktop->next = NULL;
600 pWndDesktop->child = NULL;
601 pWndDesktop->parent = NULL;
602 pWndDesktop->owner = NULL;
603 pWndDesktop->class = class;
604 pWndDesktop->dwMagic = WND_MAGIC;
605 pWndDesktop->hwndSelf = hwndDesktop;
606 pWndDesktop->hInstance = 0;
607 pWndDesktop->rectWindow.left = 0;
608 pWndDesktop->rectWindow.top = 0;
609 pWndDesktop->rectWindow.right = GetSystemMetrics(SM_CXSCREEN);
610 pWndDesktop->rectWindow.bottom = GetSystemMetrics(SM_CYSCREEN);
611 pWndDesktop->rectClient = pWndDesktop->rectWindow;
612 pWndDesktop->text = NULL;
613 pWndDesktop->hmemTaskQ = GetFastQueue16();
614 pWndDesktop->hrgnUpdate = 0;
615 pWndDesktop->hwndLastActive = hwndDesktop;
616 pWndDesktop->dwStyle = WS_VISIBLE | WS_CLIPCHILDREN |
618 pWndDesktop->dwExStyle = 0;
619 pWndDesktop->clsStyle = clsStyle;
620 pWndDesktop->dce = NULL;
621 pWndDesktop->pVScroll = NULL;
622 pWndDesktop->pHScroll = NULL;
623 pWndDesktop->pProp = NULL;
624 pWndDesktop->wIDmenu = 0;
625 pWndDesktop->helpContext = 0;
626 pWndDesktop->flags = Options.desktopGeometry ? WIN_NATIVE : 0;
627 pWndDesktop->hSysMenu = 0;
628 pWndDesktop->userdata = 0;
629 pWndDesktop->winproc = winproc;
630 pWndDesktop->cbWndExtra = wndExtra;
631 pWndDesktop->irefCount = 0;
633 if(!pWndDesktop->pDriver->pCreateDesktopWindow(pWndDesktop)) return FALSE;
635 SendMessageW( hwndDesktop, WM_NCCREATE, 0, 0 );
636 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
641 /***********************************************************************
644 * Fix the coordinates - Helper for WIN_CreateWindowEx.
645 * returns default show mode in sw.
646 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
648 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
650 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
651 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
653 if (cs->style & (WS_CHILD | WS_POPUP))
655 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
656 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
658 else /* overlapped window */
662 GetStartupInfoA( &info );
664 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
666 /* Never believe Microsoft's documentation... CreateWindowEx doc says
667 * that if an overlapped window is created with WS_VISIBLE style bit
668 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
669 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
672 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
673 * 2) it does not ignore the y parameter as the docs claim; instead, it
674 * uses it as second parameter to ShowWindow() unless y is either
675 * CW_USEDEFAULT or CW_USEDEFAULT16.
677 * The fact that we didn't do 2) caused bogus windows pop up when wine
678 * was running apps that were using this obscure feature. Example -
679 * calc.exe that comes with Win98 (only Win98, it's different from
680 * the one that comes with Win95 and NT)
682 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
683 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
684 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
687 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
689 if (info.dwFlags & STARTF_USESIZE)
691 cs->cx = info.dwXSize;
692 cs->cy = info.dwYSize;
694 else /* if no other hint from the app, pick 3/4 of the screen real estate */
697 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
698 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
699 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
706 /***********************************************************************
709 * Implementation of CreateWindowEx().
711 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
712 WINDOWPROCTYPE type )
715 struct tagCLASS *classPtr;
718 HWND16 hwnd, hwndLinkAfter;
719 POINT maxSize, maxPos, minTrack, maxTrack;
724 LRESULT (CALLBACK *localSend32)(HWND, UINT, WPARAM, LPARAM);
726 TRACE("%s %s %08lx %08lx %d,%d %dx%d %04x %04x %08x %p\n",
727 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszName) : debugres_a(cs->lpszName),
728 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszClass) : debugres_a(cs->lpszClass),
729 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
730 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
732 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
733 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
735 /* Find the parent window */
739 /* Make sure parent is valid */
740 if (!IsWindow( cs->hwndParent ))
742 WARN("Bad parent %04x\n", cs->hwndParent );
745 } else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP)) {
746 WARN("No parent for child window\n" );
747 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
750 /* Find the window class */
751 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
752 &wndExtra, &winproc, &clsStyle, &dce )))
754 WARN("Bad class '%s'\n", cs->lpszClass );
758 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
760 /* Create the window structure */
762 if (!(hwnd = USER_HEAP_ALLOC( sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
764 TRACE("out of memory\n" );
768 /* Fill the window structure */
770 wndPtr = WIN_LockWndPtr((WND *) USER_HEAP_LIN_ADDR( hwnd ));
772 wndPtr->child = NULL;
774 if ((cs->style & WS_CHILD) && cs->hwndParent)
776 wndPtr->parent = WIN_FindWndPtr( cs->hwndParent );
777 wndPtr->owner = NULL;
778 WIN_ReleaseWndPtr(wndPtr->parent);
782 wndPtr->parent = pWndDesktop;
783 if (!cs->hwndParent || (cs->hwndParent == pWndDesktop->hwndSelf))
784 wndPtr->owner = NULL;
787 WND *tmpWnd = WIN_FindWndPtr(cs->hwndParent);
788 wndPtr->owner = WIN_GetTopParentPtr(tmpWnd);
789 WIN_ReleaseWndPtr(wndPtr->owner);
790 WIN_ReleaseWndPtr(tmpWnd);
795 wndPtr->pDriver = wndPtr->parent->pDriver;
796 wndPtr->pDriver->pInitialize(wndPtr);
798 wndPtr->class = classPtr;
799 wndPtr->winproc = winproc;
800 wndPtr->dwMagic = WND_MAGIC;
801 wndPtr->hwndSelf = hwnd;
802 wndPtr->hInstance = cs->hInstance;
804 wndPtr->hmemTaskQ = GetFastQueue16();
805 wndPtr->hrgnUpdate = 0;
807 wndPtr->hwndLastActive = hwnd;
808 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
809 wndPtr->dwExStyle = cs->dwExStyle;
810 wndPtr->clsStyle = clsStyle;
812 wndPtr->helpContext = 0;
813 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
814 wndPtr->pVScroll = NULL;
815 wndPtr->pHScroll = NULL;
816 wndPtr->pProp = NULL;
817 wndPtr->userdata = 0;
818 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU)
819 ? MENU_GetSysMenu( hwnd, 0 ) : 0;
820 wndPtr->cbWndExtra = wndExtra;
821 wndPtr->irefCount = 1;
823 if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
825 /* Call the WH_CBT hook */
827 hwndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
828 ? HWND_BOTTOM : HWND_TOP;
830 if (HOOK_IsHooked( WH_CBT ))
836 cbtc.hwndInsertAfter = hwndLinkAfter;
837 ret = (type == WIN_PROC_32W) ? HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND, hwnd, (LPARAM)&cbtc)
838 : HOOK_CallHooksA(WH_CBT, HCBT_CREATEWND, hwnd, (LPARAM)&cbtc);
841 TRACE("CBT-hook returned 0\n");
842 wndPtr->pDriver->pFinalize(wndPtr);
843 USER_HEAP_FREE( hwnd );
844 CLASS_RemoveWindow( classPtr );
850 /* Correct the window style */
852 if (!(cs->style & WS_CHILD))
854 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
855 if (!(cs->style & WS_POPUP))
857 wndPtr->dwStyle |= WS_CAPTION;
858 wndPtr->flags |= WIN_NEED_SIZE;
862 /* Get class or window DC if needed */
864 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
865 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
866 else wndPtr->dce = NULL;
868 /* Initialize the dimensions before sending WM_GETMINMAXINFO */
870 wndPtr->rectWindow.left = cs->x;
871 wndPtr->rectWindow.top = cs->y;
872 wndPtr->rectWindow.right = cs->x + cs->cx;
873 wndPtr->rectWindow.bottom = cs->y + cs->cy;
874 wndPtr->rectClient = wndPtr->rectWindow;
876 /* Send the WM_GETMINMAXINFO message and fix the size if needed */
878 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
880 WINPOS_GetMinMaxInfo( wndPtr, &maxSize, &maxPos, &minTrack, &maxTrack);
881 if (maxSize.x < cs->cx) cs->cx = maxSize.x;
882 if (maxSize.y < cs->cy) cs->cy = maxSize.y;
883 if (cs->cx < minTrack.x ) cs->cx = minTrack.x;
884 if (cs->cy < minTrack.y ) cs->cy = minTrack.y;
887 if (cs->cx < 0) cs->cx = 0;
888 if (cs->cy < 0) cs->cy = 0;
890 wndPtr->rectWindow.left = cs->x;
891 wndPtr->rectWindow.top = cs->y;
892 wndPtr->rectWindow.right = cs->x + cs->cx;
893 wndPtr->rectWindow.bottom = cs->y + cs->cy;
894 wndPtr->rectClient = wndPtr->rectWindow;
896 if(!wndPtr->pDriver->pCreateWindow(wndPtr, cs, type == WIN_PROC_32W))
902 /* Set the window menu */
904 if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
906 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
909 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
912 if (HIWORD(cs->hInstance))
913 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
915 cs->hMenu = LoadMenu16(cs->hInstance,menuName);
917 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
921 else wndPtr->wIDmenu = (UINT)cs->hMenu;
923 /* Send the WM_CREATE message
924 * Perhaps we shouldn't allow width/height changes as well.
925 * See p327 in "Internals".
928 maxPos.x = wndPtr->rectWindow.left; maxPos.y = wndPtr->rectWindow.top;
930 localSend32 = (type == WIN_PROC_32W) ? SendMessageW : SendMessageA;
931 if( (*localSend32)( hwnd, WM_NCCREATE, 0, (LPARAM)cs) )
933 /* Insert the window in the linked list */
935 WIN_LinkWindow( hwnd, hwndLinkAfter );
937 WINPOS_SendNCCalcSize( hwnd, FALSE, &wndPtr->rectWindow,
938 NULL, NULL, 0, &wndPtr->rectClient );
939 OffsetRect(&wndPtr->rectWindow, maxPos.x - wndPtr->rectWindow.left,
940 maxPos.y - wndPtr->rectWindow.top);
941 if( ((*localSend32)( hwnd, WM_CREATE, 0, (LPARAM)cs )) != -1 )
943 /* Send the size messages */
945 if (!(wndPtr->flags & WIN_NEED_SIZE))
948 if (((wndPtr->rectClient.right-wndPtr->rectClient.left) <0)
949 ||((wndPtr->rectClient.bottom-wndPtr->rectClient.top)<0))
950 WARN("sending bogus WM_SIZE message 0x%08lx\n",
951 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
952 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
953 (*localSend32)( hwnd, WM_SIZE, SIZE_RESTORED,
954 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
955 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
956 (*localSend32)( hwnd, WM_MOVE, 0,
957 MAKELONG( wndPtr->rectClient.left,
958 wndPtr->rectClient.top ) );
961 /* Show the window, maximizing or minimizing if needed */
963 if (wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE))
966 UINT16 swFlag = (wndPtr->dwStyle & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
967 wndPtr->dwStyle &= ~(WS_MAXIMIZE | WS_MINIMIZE);
968 WINPOS_MinMaximize( wndPtr, swFlag, &newPos );
969 swFlag = ((wndPtr->dwStyle & WS_CHILD) || GetActiveWindow())
970 ? SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED
971 : SWP_NOZORDER | SWP_FRAMECHANGED;
972 SetWindowPos( hwnd, 0, newPos.left, newPos.top,
973 newPos.right, newPos.bottom, swFlag );
976 if( (wndPtr->dwStyle & WS_CHILD) && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
978 /* Notify the parent window only */
980 SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
981 MAKEWPARAM(WM_CREATE, wndPtr->wIDmenu), (LPARAM)hwnd );
982 if( !IsWindow(hwnd) )
989 if (cs->style & WS_VISIBLE) ShowWindow( hwnd, sw );
991 /* Call WH_SHELL hook */
993 if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
994 HOOK_CallHooks16( WH_SHELL, HSHELL_WINDOWCREATED, hwnd, 0 );
996 TRACE("created window %04x\n", hwnd);
1000 WIN_UnlinkWindow( hwnd );
1003 /* Abort window creation */
1005 WARN("aborted by WM_xxCREATE!\n");
1006 WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr ));
1007 CLASS_RemoveWindow( classPtr );
1010 WIN_ReleaseWndPtr(wndPtr);
1016 /***********************************************************************
1017 * CreateWindow (USER.41)
1019 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
1020 DWORD style, INT16 x, INT16 y, INT16 width,
1021 INT16 height, HWND16 parent, HMENU16 menu,
1022 HINSTANCE16 instance, LPVOID data )
1024 return CreateWindowEx16( 0, className, windowName, style,
1025 x, y, width, height, parent, menu, instance, data );
1029 /***********************************************************************
1030 * CreateWindowEx (USER.452)
1032 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1033 LPCSTR windowName, DWORD style, INT16 x,
1034 INT16 y, INT16 width, INT16 height,
1035 HWND16 parent, HMENU16 menu,
1036 HINSTANCE16 instance, LPVOID data )
1042 /* Find the class atom */
1044 if (HIWORD(className))
1046 if (!(classAtom = GlobalFindAtomA( className )))
1048 ERR( "bad class name %s\n", debugres_a(className) );
1054 classAtom = LOWORD(className);
1055 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1057 ERR( "bad atom %x\n", classAtom);
1063 /* Fix the coordinates */
1065 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1066 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1067 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1068 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1070 /* Create the window */
1072 cs.lpCreateParams = data;
1073 cs.hInstance = (HINSTANCE)instance;
1074 cs.hMenu = (HMENU)menu;
1075 cs.hwndParent = (HWND)parent;
1077 cs.lpszName = windowName;
1078 cs.lpszClass = className;
1079 cs.dwExStyle = exStyle;
1081 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 );
1085 /***********************************************************************
1086 * CreateWindowExA (USER32.@)
1088 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1089 LPCSTR windowName, DWORD style, INT x,
1090 INT y, INT width, INT height,
1091 HWND parent, HMENU menu,
1092 HINSTANCE instance, LPVOID data )
1099 instance=GetModuleHandleA(NULL);
1101 if(exStyle & WS_EX_MDICHILD)
1102 return MDI_CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1104 /* Find the class atom */
1106 if (HIWORD(className))
1108 if (!(classAtom = GlobalFindAtomA( className )))
1110 ERR( "bad class name %s\n", debugres_a(className) );
1116 classAtom = LOWORD(className);
1117 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1119 ERR( "bad atom %x\n", classAtom);
1125 /* Create the window */
1127 cs.lpCreateParams = data;
1128 cs.hInstance = instance;
1130 cs.hwndParent = parent;
1136 cs.lpszName = windowName;
1137 cs.lpszClass = className;
1138 cs.dwExStyle = exStyle;
1140 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1144 /***********************************************************************
1145 * CreateWindowExW (USER32.@)
1147 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1148 LPCWSTR windowName, DWORD style, INT x,
1149 INT y, INT width, INT height,
1150 HWND parent, HMENU menu,
1151 HINSTANCE instance, LPVOID data )
1158 instance=GetModuleHandleA(NULL);
1160 if(exStyle & WS_EX_MDICHILD)
1161 return MDI_CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1163 /* Find the class atom */
1165 if (HIWORD(className))
1167 if (!(classAtom = GlobalFindAtomW( className )))
1169 ERR( "bad class name %s\n", debugres_w(className) );
1175 classAtom = LOWORD(className);
1176 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1178 ERR( "bad atom %x\n", classAtom);
1184 /* Create the window */
1186 cs.lpCreateParams = data;
1187 cs.hInstance = instance;
1189 cs.hwndParent = parent;
1195 cs.lpszName = windowName;
1196 cs.lpszClass = className;
1197 cs.dwExStyle = exStyle;
1199 /* Note: we rely on the fact that CREATESTRUCTA and */
1200 /* CREATESTRUCTW have the same layout. */
1201 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1204 /***********************************************************************
1205 * WIN_SendDestroyMsg
1207 static void WIN_SendDestroyMsg( WND* pWnd )
1209 if( CARET_GetHwnd() == pWnd->hwndSelf ) DestroyCaret();
1210 USER_Driver.pResetSelectionOwner( pWnd, TRUE );
1213 * Send the WM_DESTROY to the window.
1215 SendMessageA( pWnd->hwndSelf, WM_DESTROY, 0, 0);
1218 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1219 * make sure that the window still exists when we come back.
1221 if (IsWindow(pWnd->hwndSelf))
1223 HWND* pWndArray = NULL;
1228 * Now, if the window has kids, we have to send WM_DESTROY messages
1229 * recursively to it's kids. It seems that those calls can also
1230 * trigger re-entrant calls to DestroyWindow for the kids so we must
1231 * protect against corruption of the list of siblings. We first build
1232 * a list of HWNDs representing all the kids.
1234 pChild = WIN_LockWndPtr(pWnd->child);
1238 WIN_UpdateWndPtr(&pChild,pChild->next);
1242 * If there are no kids, we're done.
1247 pWndArray = HeapAlloc(GetProcessHeap(), 0, nKidCount*sizeof(HWND));
1252 if (pWndArray==NULL)
1256 * Now, enumerate all the kids in a list, since we wait to make the SendMessage
1257 * call, our linked list of siblings should be safe.
1260 pChild = WIN_LockWndPtr(pWnd->child);
1263 pWndArray[nKidCount] = pChild->hwndSelf;
1265 WIN_UpdateWndPtr(&pChild,pChild->next);
1269 * Now that we have a list, go through that list again and send the destroy
1270 * message to those windows. We are using the HWND to retrieve the
1271 * WND pointer so we are effectively checking that all the kid windows are
1272 * still valid before sending the message.
1276 pChild = WIN_FindWndPtr(pWndArray[--nKidCount]);
1280 WIN_SendDestroyMsg( pChild );
1281 WIN_ReleaseWndPtr(pChild);
1288 HeapFree(GetProcessHeap(), 0, pWndArray);
1291 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1295 /***********************************************************************
1296 * DestroyWindow (USER.53)
1298 BOOL16 WINAPI DestroyWindow16( HWND16 hwnd )
1300 return DestroyWindow(hwnd);
1304 /***********************************************************************
1305 * DestroyWindow (USER32.@)
1307 BOOL WINAPI DestroyWindow( HWND hwnd )
1312 BOOL bFocusSet = FALSE;
1314 TRACE("(%04x)\n", hwnd);
1316 /* Initialization */
1318 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1319 if (wndPtr == pWndDesktop)
1321 retvalue = FALSE; /* Can't destroy desktop */
1325 /* Look whether the focus is within the tree of windows we will
1329 while (h && (GetWindowLongA(h,GWL_STYLE) & WS_CHILD))
1333 SetFocus(GetWindowLongA(hwnd,GWL_HWNDPARENT));
1337 h = GetWindowLongA(h,GWL_HWNDPARENT);
1339 /* If the focus is on the window we will destroy and it has no parent,
1340 * set the focus to 0.
1342 if (! bFocusSet && (h == hwnd))
1344 if (!(GetWindowLongA(h,GWL_STYLE) & WS_CHILD))
1350 if( HOOK_CallHooks16( WH_CBT, HCBT_DESTROYWND, hwnd, 0L) )
1356 if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
1358 HOOK_CallHooks16( WH_SHELL, HSHELL_WINDOWDESTROYED, hwnd, 0L );
1359 /* FIXME: clean up palette - see "Internals" p.352 */
1362 if( !QUEUE_IsExitingQueue(wndPtr->hmemTaskQ) )
1363 if( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
1365 /* Notify the parent window only */
1366 SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
1367 MAKEWPARAM(WM_DESTROY, wndPtr->wIDmenu), (LPARAM)hwnd );
1368 if( !IsWindow(hwnd) )
1375 USER_Driver.pResetSelectionOwner( wndPtr, FALSE ); /* before the window is unmapped */
1377 /* Hide the window */
1379 if (wndPtr->dwStyle & WS_VISIBLE)
1381 SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_HIDEWINDOW |
1382 SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|
1383 ((QUEUE_IsExitingQueue(wndPtr->hmemTaskQ))?SWP_DEFERERASE:0) );
1384 if (!IsWindow(hwnd))
1391 /* Recursively destroy owned windows */
1393 if( !(wndPtr->dwStyle & WS_CHILD) )
1395 /* make sure top menu popup doesn't get destroyed */
1396 MENU_PatchResidentPopup( (HQUEUE16)0xFFFF, wndPtr );
1400 WND *siblingPtr = WIN_LockWndPtr(wndPtr->parent->child); /* First sibling */
1403 if (siblingPtr->owner == wndPtr)
1405 if (siblingPtr->hmemTaskQ == wndPtr->hmemTaskQ)
1408 siblingPtr->owner = NULL;
1410 WIN_UpdateWndPtr(&siblingPtr,siblingPtr->next);
1414 DestroyWindow( siblingPtr->hwndSelf );
1415 WIN_ReleaseWndPtr(siblingPtr);
1420 if( !Options.managed || EVENT_CheckFocus() )
1421 WINPOS_ActivateOtherWindow(wndPtr);
1423 if( wndPtr->owner &&
1424 wndPtr->owner->hwndLastActive == wndPtr->hwndSelf )
1425 wndPtr->owner->hwndLastActive = wndPtr->owner->hwndSelf;
1428 /* Send destroy messages */
1430 WIN_SendDestroyMsg( wndPtr );
1431 if (!IsWindow(hwnd))
1437 /* Unlink now so we won't bother with the children later on */
1439 if( wndPtr->parent ) WIN_UnlinkWindow(hwnd);
1441 /* Destroy the window storage */
1443 WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr ));
1446 WIN_ReleaseWndPtr(wndPtr);
1451 /***********************************************************************
1452 * CloseWindow (USER.43)
1454 BOOL16 WINAPI CloseWindow16( HWND16 hwnd )
1456 return CloseWindow( hwnd );
1460 /***********************************************************************
1461 * CloseWindow (USER32.@)
1463 BOOL WINAPI CloseWindow( HWND hwnd )
1465 WND * wndPtr = WIN_FindWndPtr( hwnd );
1468 if (!wndPtr || (wndPtr->dwStyle & WS_CHILD))
1473 ShowWindow( hwnd, SW_MINIMIZE );
1476 WIN_ReleaseWndPtr(wndPtr);
1482 /***********************************************************************
1483 * OpenIcon (USER.44)
1485 BOOL16 WINAPI OpenIcon16( HWND16 hwnd )
1487 return OpenIcon( hwnd );
1491 /***********************************************************************
1492 * OpenIcon (USER32.@)
1494 BOOL WINAPI OpenIcon( HWND hwnd )
1496 if (!IsIconic( hwnd )) return FALSE;
1497 ShowWindow( hwnd, SW_SHOWNORMAL );
1502 /***********************************************************************
1505 * Implementation of FindWindow() and FindWindowEx().
1507 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className,
1515 if (!(pWnd = WIN_FindWndPtr( child ))) return 0;
1518 if (!pWnd->parent || (pWnd->parent->hwndSelf != parent))
1524 else if (pWnd->parent != pWndDesktop)
1529 WIN_UpdateWndPtr(&pWnd,pWnd->next);
1533 if (!(pWnd = parent ? WIN_FindWndPtr(parent) : WIN_LockWndPtr(pWndDesktop)))
1538 WIN_UpdateWndPtr(&pWnd,pWnd->child);
1546 for ( ; pWnd ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
1548 if (className && (GetClassWord(pWnd->hwndSelf, GCW_ATOM) != className))
1549 continue; /* Not the right class */
1551 /* Now check the title */
1555 retvalue = pWnd->hwndSelf;
1558 if (pWnd->text && !strcmpW( pWnd->text, title ))
1560 retvalue = pWnd->hwndSelf;
1565 /* In this case we need to check whether other processes
1566 own a window with the given paramters on the Desktop,
1567 but we don't, so let's at least warn about it */
1568 FIXME("Returning 0 without checking other processes\n");
1570 WIN_ReleaseWndPtr(pWnd);
1576 /***********************************************************************
1577 * FindWindow (USER.50)
1579 HWND16 WINAPI FindWindow16( LPCSTR className, LPCSTR title )
1581 return FindWindowA( className, title );
1585 /***********************************************************************
1586 * FindWindowEx (USER.427)
1588 HWND16 WINAPI FindWindowEx16( HWND16 parent, HWND16 child, LPCSTR className, LPCSTR title )
1590 return FindWindowExA( parent, child, className, title );
1594 /***********************************************************************
1595 * FindWindowA (USER32.@)
1597 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1599 HWND ret = FindWindowExA( 0, 0, className, title );
1600 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1605 /***********************************************************************
1606 * FindWindowExA (USER32.@)
1608 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1609 LPCSTR className, LPCSTR title )
1617 /* If the atom doesn't exist, then no class */
1618 /* with this name exists either. */
1619 if (!(atom = GlobalFindAtomA( className )))
1621 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1626 buffer = HEAP_strdupAtoW( GetProcessHeap(), 0, title );
1627 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1628 HeapFree( GetProcessHeap(), 0, buffer );
1633 /***********************************************************************
1634 * FindWindowExW (USER32.@)
1636 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1637 LPCWSTR className, LPCWSTR title )
1643 /* If the atom doesn't exist, then no class */
1644 /* with this name exists either. */
1645 if (!(atom = GlobalFindAtomW( className )))
1647 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1651 return WIN_FindWindow( parent, child, atom, title );
1655 /***********************************************************************
1656 * FindWindowW (USER32.@)
1658 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1660 return FindWindowExW( 0, 0, className, title );
1664 /**********************************************************************
1666 * returns a locked pointer
1668 WND *WIN_GetDesktop(void)
1670 return WIN_LockWndPtr(pWndDesktop);
1672 /**********************************************************************
1673 * WIN_ReleaseDesktop
1674 * unlock the desktop pointer
1676 void WIN_ReleaseDesktop(void)
1678 WIN_ReleaseWndPtr(pWndDesktop);
1682 /**********************************************************************
1683 * GetDesktopWindow (USER.286)
1685 HWND16 WINAPI GetDesktopWindow16(void)
1687 return (HWND16)pWndDesktop->hwndSelf;
1691 /**********************************************************************
1692 * GetDesktopWindow (USER32.@)
1694 HWND WINAPI GetDesktopWindow(void)
1696 if (pWndDesktop) return pWndDesktop->hwndSelf;
1697 ERR( "You need the -desktop option when running with native USER\n" );
1703 /**********************************************************************
1704 * GetDesktopHwnd (USER.278)
1706 * Exactly the same thing as GetDesktopWindow(), but not documented.
1707 * Don't ask me why...
1709 HWND16 WINAPI GetDesktopHwnd16(void)
1711 return (HWND16)pWndDesktop->hwndSelf;
1715 /*******************************************************************
1716 * EnableWindow (USER.34)
1718 BOOL16 WINAPI EnableWindow16( HWND16 hwnd, BOOL16 enable )
1720 return EnableWindow( hwnd, enable );
1724 /*******************************************************************
1725 * EnableWindow (USER32.@)
1727 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1732 TRACE("EnableWindow32: ( %x, %d )\n", hwnd, enable);
1734 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1735 if (enable && (wndPtr->dwStyle & WS_DISABLED))
1738 wndPtr->dwStyle &= ~WS_DISABLED;
1740 if( wndPtr->flags & WIN_NATIVE )
1741 wndPtr->pDriver->pSetHostAttr( wndPtr, HAK_ACCEPTFOCUS, TRUE );
1743 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1747 else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
1749 SendMessageA( wndPtr->hwndSelf, WM_CANCELMODE, 0, 0);
1751 /* Disable window */
1752 wndPtr->dwStyle |= WS_DISABLED;
1754 if( wndPtr->flags & WIN_NATIVE )
1755 wndPtr->pDriver->pSetHostAttr( wndPtr, HAK_ACCEPTFOCUS, FALSE );
1757 if (hwnd == GetFocus())
1759 SetFocus( 0 ); /* A disabled window can't have the focus */
1761 if (hwnd == GetCapture())
1763 ReleaseCapture(); /* A disabled window can't capture the mouse */
1765 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1769 retvalue = ((wndPtr->dwStyle & WS_DISABLED) != 0);
1771 WIN_ReleaseWndPtr(wndPtr);
1776 /***********************************************************************
1777 * IsWindowEnabled (USER.35)
1779 BOOL16 WINAPI IsWindowEnabled16(HWND16 hWnd)
1781 return IsWindowEnabled(hWnd);
1785 /***********************************************************************
1786 * IsWindowEnabled (USER32.@)
1788 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1793 if (!(wndPtr = WIN_FindWndPtr(hWnd))) return FALSE;
1794 retvalue = !(wndPtr->dwStyle & WS_DISABLED);
1795 WIN_ReleaseWndPtr(wndPtr);
1801 /***********************************************************************
1802 * IsWindowUnicode (USER32.@)
1804 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1809 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1810 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1811 WIN_ReleaseWndPtr(wndPtr);
1816 /**********************************************************************
1817 * GetWindowWord (USER.133)
1819 WORD WINAPI GetWindowWord16( HWND16 hwnd, INT16 offset )
1821 return GetWindowWord( hwnd, offset );
1825 /**********************************************************************
1826 * GetWindowWord (USER32.@)
1828 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1831 WND * wndPtr = WIN_FindWndPtr( hwnd );
1832 if (!wndPtr) return 0;
1835 if (offset + sizeof(WORD) > wndPtr->cbWndExtra)
1837 WARN("Invalid offset %d\n", offset );
1841 retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1847 if (HIWORD(wndPtr->wIDmenu))
1848 WARN("GWW_ID: discards high bits of 0x%08x!\n",
1850 retvalue = (WORD)wndPtr->wIDmenu;
1852 case GWW_HWNDPARENT:
1853 retvalue = GetParent(hwnd);
1856 if (HIWORD(wndPtr->hInstance))
1857 WARN("GWW_HINSTANCE: discards high bits of 0x%08x!\n",
1859 retvalue = (WORD)wndPtr->hInstance;
1862 WARN("Invalid offset %d\n", offset );
1867 WIN_ReleaseWndPtr(wndPtr);
1871 /**********************************************************************
1872 * SetWindowWord (USER.134)
1874 WORD WINAPI SetWindowWord16( HWND16 hwnd, INT16 offset, WORD newval )
1876 return SetWindowWord( hwnd, offset, newval );
1880 /**********************************************************************
1881 * SetWindowWord (USER32.@)
1883 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1886 WND * wndPtr = WIN_FindWndPtr( hwnd );
1887 if (!wndPtr) return 0;
1890 if (offset + sizeof(WORD) > wndPtr->cbWndExtra)
1892 WARN("Invalid offset %d\n", offset );
1896 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1900 case GWW_ID: ptr = (WORD *)&wndPtr->wIDmenu; break;
1901 case GWW_HINSTANCE: ptr = (WORD *)&wndPtr->hInstance; break;
1902 case GWW_HWNDPARENT: retval = SetParent( hwnd, newval );
1905 WARN("Invalid offset %d\n", offset );
1912 WIN_ReleaseWndPtr(wndPtr);
1917 /**********************************************************************
1920 * Helper function for GetWindowLong().
1922 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1925 WND * wndPtr = WIN_FindWndPtr( hwnd );
1926 if (!wndPtr) return 0;
1929 if (offset + sizeof(LONG) > wndPtr->cbWndExtra)
1931 WARN("Invalid offset %d\n", offset );
1935 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1936 /* Special case for dialog window procedure */
1937 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1939 retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1946 case GWL_USERDATA: retvalue = wndPtr->userdata;
1948 case GWL_STYLE: retvalue = wndPtr->dwStyle;
1950 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle;
1952 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu;
1954 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc,
1957 case GWL_HWNDPARENT: retvalue = GetParent(hwnd);
1959 case GWL_HINSTANCE: retvalue = wndPtr->hInstance;
1962 WARN("Unknown offset %d\n", offset );
1966 WIN_ReleaseWndPtr(wndPtr);
1971 /**********************************************************************
1974 * Helper function for SetWindowLong().
1976 * 0 is the failure code. However, in the case of failure SetLastError
1977 * must be set to distinguish between a 0 return value and a failure.
1979 * FIXME: The error values for SetLastError may not be right. Can
1980 * someone check with the real thing?
1982 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1983 WINDOWPROCTYPE type )
1986 WND * wndPtr = WIN_FindWndPtr( hwnd );
1989 TRACE("%x=%p %x %lx %x\n",hwnd, wndPtr, offset, newval, type);
1993 /* Is this the right error? */
1994 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2000 if (offset + sizeof(LONG) > wndPtr->cbWndExtra)
2002 WARN("Invalid offset %d\n", offset );
2004 /* Is this the right error? */
2005 SetLastError( ERROR_OUTOFMEMORY );
2010 ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
2011 /* Special case for dialog window procedure */
2012 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
2014 retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
2015 WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
2016 type, WIN_PROC_WINDOW );
2023 ptr = (DWORD*)&wndPtr->wIDmenu;
2026 retval = SetWindowWord( hwnd, offset, newval );
2029 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
2030 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
2031 type, WIN_PROC_WINDOW );
2034 style.styleOld = wndPtr->dwStyle;
2035 newval &= ~(WS_CHILD); /* this bit can't be changed this way */
2036 style.styleNew = newval | (style.styleOld & (WS_CHILD));
2038 if (wndPtr->flags & WIN_ISWIN32)
2039 SendMessageA(hwnd,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style);
2040 wndPtr->dwStyle = style.styleNew;
2041 if (wndPtr->flags & WIN_ISWIN32)
2042 SendMessageA(hwnd,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style);
2043 retval = style.styleOld;
2047 ptr = &wndPtr->userdata;
2050 style.styleOld = wndPtr->dwExStyle;
2051 style.styleNew = newval;
2052 if (wndPtr->flags & WIN_ISWIN32)
2053 SendMessageA(hwnd,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style);
2054 wndPtr->dwExStyle = newval;
2055 if (wndPtr->flags & WIN_ISWIN32)
2056 SendMessageA(hwnd,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style);
2057 retval = style.styleOld;
2061 WARN("Invalid offset %d\n", offset );
2063 /* Don't think this is right error but it should do */
2064 SetLastError( ERROR_OUTOFMEMORY );
2072 WIN_ReleaseWndPtr(wndPtr);
2077 /**********************************************************************
2078 * GetWindowLong (USER.135)
2080 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2082 return WIN_GetWindowLong( (HWND)hwnd, offset, WIN_PROC_16 );
2086 /**********************************************************************
2087 * GetWindowLongA (USER32.@)
2089 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2091 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2095 /**********************************************************************
2096 * GetWindowLongW (USER32.@)
2098 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2100 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2104 /**********************************************************************
2105 * SetWindowLong (USER.136)
2107 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2109 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_16 );
2113 /**********************************************************************
2114 * SetWindowLongA (USER32.@)
2116 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2118 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2122 /**********************************************************************
2123 * SetWindowLongW (USER32.@) Set window attribute
2125 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2126 * value in a window's extra memory.
2128 * The _hwnd_ parameter specifies the window. is the handle to a
2129 * window that has extra memory. The _newval_ parameter contains the
2130 * new attribute or extra memory value. If positive, the _offset_
2131 * parameter is the byte-addressed location in the window's extra
2132 * memory to set. If negative, _offset_ specifies the window
2133 * attribute to set, and should be one of the following values:
2135 * GWL_EXSTYLE The window's extended window style
2137 * GWL_STYLE The window's window style.
2139 * GWL_WNDPROC Pointer to the window's window procedure.
2141 * GWL_HINSTANCE The window's pplication instance handle.
2143 * GWL_ID The window's identifier.
2145 * GWL_USERDATA The window's user-specified data.
2147 * If the window is a dialog box, the _offset_ parameter can be one of
2148 * the following values:
2150 * DWL_DLGPROC The address of the window's dialog box procedure.
2152 * DWL_MSGRESULT The return value of a message
2153 * that the dialog box procedure processed.
2155 * DWL_USER Application specific information.
2159 * If successful, returns the previous value located at _offset_. Otherwise,
2164 * Extra memory for a window class is specified by a nonzero cbWndExtra
2165 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2166 * time of class creation.
2168 * Using GWL_WNDPROC to set a new window procedure effectively creates
2169 * a window subclass. Use CallWindowProc() in the new windows procedure
2170 * to pass messages to the superclass's window procedure.
2172 * The user data is reserved for use by the application which created
2175 * Do not use GWL_STYLE to change the window's WS_DISABLE style;
2176 * instead, call the EnableWindow() function to change the window's
2179 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2180 * SetParent() instead.
2183 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2184 * it sends WM_STYLECHANGING before changing the settings
2185 * and WM_STYLECHANGED afterwards.
2186 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2190 * GWL_STYLE does not dispatch WM_STYLE... messages.
2197 LONG WINAPI SetWindowLongW(
2198 HWND hwnd, /* [in] window to alter */
2199 INT offset, /* [in] offset, in bytes, of location to alter */
2200 LONG newval /* [in] new value of location */
2202 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2206 /*******************************************************************
2207 * GetWindowText (USER.36)
2209 INT16 WINAPI GetWindowText16( HWND16 hwnd, SEGPTR lpString, INT16 nMaxCount )
2211 return (INT16)SendMessage16(hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
2215 /*******************************************************************
2216 * GetWindowTextA (USER32.@)
2218 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2220 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount,
2224 /*******************************************************************
2225 * InternalGetWindowText (USER32.@)
2227 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2229 FIXME("(0x%08x,%p,0x%x),stub!\n",hwnd,lpString,nMaxCount);
2230 return GetWindowTextW(hwnd,lpString,nMaxCount);
2234 /*******************************************************************
2235 * GetWindowTextW (USER32.@)
2237 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2239 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount,
2244 /*******************************************************************
2245 * SetWindowText (USER.37)
2247 BOOL16 WINAPI SetWindowText16( HWND16 hwnd, SEGPTR lpString )
2249 return (BOOL16)SendMessage16( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2253 /*******************************************************************
2254 * SetWindowTextA (USER32.@)
2256 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2258 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2262 /*******************************************************************
2263 * SetWindowTextW (USER32.@)
2265 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2267 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2271 /*******************************************************************
2272 * GetWindowTextLength (USER.38)
2274 INT16 WINAPI GetWindowTextLength16( HWND16 hwnd )
2276 return (INT16)SendMessage16( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2280 /*******************************************************************
2281 * GetWindowTextLengthA (USER32.@)
2283 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2285 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2288 /*******************************************************************
2289 * GetWindowTextLengthW (USER32.@)
2291 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2293 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2297 /*******************************************************************
2298 * IsWindow (USER.47)
2300 BOOL16 WINAPI IsWindow16( HWND16 hwnd )
2302 CURRENT_STACK16->es = USER_HeapSel;
2303 return IsWindow( hwnd );
2307 /*******************************************************************
2308 * IsWindow (USER32.@)
2310 BOOL WINAPI IsWindow( HWND hwnd )
2315 if(!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
2316 retvalue = (wndPtr->dwMagic == WND_MAGIC);
2317 WIN_ReleaseWndPtr(wndPtr);
2323 /*****************************************************************
2324 * GetParent (USER.46)
2326 HWND16 WINAPI GetParent16( HWND16 hwnd )
2328 return (HWND16)GetParent( hwnd );
2332 /*****************************************************************
2333 * GetParent (USER32.@)
2335 HWND WINAPI GetParent( HWND hwnd )
2340 if(!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2341 if ((!(wndPtr->dwStyle & (WS_POPUP|WS_CHILD))))
2344 WIN_UpdateWndPtr(&wndPtr,((wndPtr->dwStyle & WS_CHILD) ? wndPtr->parent : wndPtr->owner));
2346 retvalue = wndPtr->hwndSelf;
2349 WIN_ReleaseWndPtr(wndPtr);
2354 /*****************************************************************
2357 * Get the top-level parent for a child window.
2358 * returns a locked pointer
2360 WND* WIN_GetTopParentPtr( WND* pWnd )
2362 WND *tmpWnd = WIN_LockWndPtr(pWnd);
2364 while( tmpWnd && (tmpWnd->dwStyle & WS_CHILD))
2366 WIN_UpdateWndPtr(&tmpWnd,tmpWnd->parent);
2371 /*****************************************************************
2374 * Get the top-level parent for a child window.
2376 HWND WIN_GetTopParent( HWND hwnd )
2379 WND *tmpPtr = WIN_FindWndPtr(hwnd);
2380 WND *wndPtr = WIN_GetTopParentPtr (tmpPtr );
2382 retvalue = wndPtr ? wndPtr->hwndSelf : 0;
2383 WIN_ReleaseWndPtr(tmpPtr);
2384 WIN_ReleaseWndPtr(wndPtr);
2389 /*****************************************************************
2390 * SetParent (USER.233)
2392 HWND16 WINAPI SetParent16( HWND16 hwndChild, HWND16 hwndNewParent )
2394 return SetParent( hwndChild, hwndNewParent );
2398 /*****************************************************************
2399 * SetParent (USER32.@)
2401 HWND WINAPI SetParent( HWND hwndChild, HWND hwndNewParent )
2410 if(!(wndPtr = WIN_FindWndPtr(hwndChild))) return 0;
2412 dwStyle = wndPtr->dwStyle;
2414 pWndNewParent = hwndNewParent ? WIN_FindWndPtr(hwndNewParent)
2415 : WIN_LockWndPtr(pWndDesktop);
2417 /* Windows hides the window first, then shows it again
2418 * including the WM_SHOWWINDOW messages and all */
2419 if (dwStyle & WS_VISIBLE)
2420 ShowWindow( hwndChild, SW_HIDE );
2422 pWndOldParent = WIN_LockWndPtr((*wndPtr->pDriver->pSetParent)(wndPtr, pWndNewParent));
2424 /* SetParent additionally needs to make hwndChild the topmost window
2425 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2426 WM_WINDOWPOSCHANGED notification messages.
2428 SetWindowPos( hwndChild, HWND_TOPMOST, 0, 0, 0, 0,
2429 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|((dwStyle & WS_VISIBLE)?SWP_SHOWWINDOW:0));
2430 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2431 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2433 retvalue = pWndOldParent?pWndOldParent->hwndSelf:0;
2435 WIN_ReleaseWndPtr(pWndOldParent);
2436 WIN_ReleaseWndPtr(pWndNewParent);
2437 WIN_ReleaseWndPtr(wndPtr);
2443 /*******************************************************************
2446 BOOL16 WINAPI IsChild16( HWND16 parent, HWND16 child )
2448 return IsChild(parent,child);
2452 /*******************************************************************
2453 * IsChild (USER32.@)
2455 BOOL WINAPI IsChild( HWND parent, HWND child )
2457 WND * wndPtr = WIN_FindWndPtr( child );
2458 while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
2460 WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
2461 if (wndPtr->hwndSelf == parent)
2463 WIN_ReleaseWndPtr(wndPtr);
2467 WIN_ReleaseWndPtr(wndPtr);
2472 /***********************************************************************
2473 * IsWindowVisible (USER.49)
2475 BOOL16 WINAPI IsWindowVisible16( HWND16 hwnd )
2477 return IsWindowVisible(hwnd);
2481 /***********************************************************************
2482 * IsWindowVisible (USER32.@)
2484 BOOL WINAPI IsWindowVisible( HWND hwnd )
2487 WND *wndPtr = WIN_FindWndPtr( hwnd );
2488 while (wndPtr && (wndPtr->dwStyle & WS_CHILD))
2490 if (!(wndPtr->dwStyle & WS_VISIBLE))
2492 WIN_ReleaseWndPtr(wndPtr);
2495 WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
2497 retval = (wndPtr && (wndPtr->dwStyle & WS_VISIBLE));
2498 WIN_ReleaseWndPtr(wndPtr);
2504 /***********************************************************************
2505 * WIN_IsWindowDrawable
2507 * hwnd is drawable when it is visible, all parents are not
2508 * minimized, and it is itself not minimized unless we are
2509 * trying to draw its default class icon.
2511 BOOL WIN_IsWindowDrawable( WND* wnd, BOOL icon )
2513 if (!(wnd->dwStyle & WS_VISIBLE)) return FALSE;
2514 if ((wnd->dwStyle & WS_MINIMIZE) &&
2515 icon && GetClassLongA( wnd->hwndSelf, GCL_HICON )) return FALSE;
2516 for(wnd = wnd->parent; wnd; wnd = wnd->parent)
2517 if( wnd->dwStyle & WS_MINIMIZE ||
2518 !(wnd->dwStyle & WS_VISIBLE) ) break;
2519 return (wnd == NULL);
2523 /*******************************************************************
2524 * GetTopWindow (USER.229)
2526 HWND16 WINAPI GetTopWindow16( HWND16 hwnd )
2528 return GetTopWindow(hwnd);
2532 /*******************************************************************
2533 * GetTopWindow (USER32.@)
2535 HWND WINAPI GetTopWindow( HWND hwnd )
2538 WND * wndPtr = (hwnd) ?
2539 WIN_FindWndPtr( hwnd ) : WIN_GetDesktop();
2541 if (wndPtr && wndPtr->child)
2542 retval = wndPtr->child->hwndSelf;
2544 WIN_ReleaseWndPtr(wndPtr);
2549 /*******************************************************************
2550 * GetWindow (USER.262)
2552 HWND16 WINAPI GetWindow16( HWND16 hwnd, WORD rel )
2554 return GetWindow( hwnd,rel );
2558 /*******************************************************************
2559 * GetWindow (USER32.@)
2561 HWND WINAPI GetWindow( HWND hwnd, WORD rel )
2565 WND * wndPtr = WIN_FindWndPtr( hwnd );
2566 if (!wndPtr) return 0;
2570 retval = wndPtr->parent ? wndPtr->parent->child->hwndSelf : 0;
2574 if (!wndPtr->parent)
2576 retval = 0; /* Desktop window */
2579 while (wndPtr->next)
2581 WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
2583 retval = wndPtr->hwndSelf;
2587 retval = wndPtr->next ? wndPtr->next->hwndSelf : 0;
2591 if (!wndPtr->parent)
2593 retval = 0; /* Desktop window */
2596 WIN_UpdateWndPtr(&wndPtr,wndPtr->parent->child); /* First sibling */
2597 if (wndPtr->hwndSelf == hwnd)
2599 retval = 0; /* First in list */
2602 while (wndPtr->next)
2604 if (wndPtr->next->hwndSelf == hwnd)
2606 retval = wndPtr->hwndSelf;
2609 WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
2615 retval = wndPtr->owner ? wndPtr->owner->hwndSelf : 0;
2619 retval = wndPtr->child ? wndPtr->child->hwndSelf : 0;
2624 WIN_ReleaseWndPtr(wndPtr);
2629 /*******************************************************************
2630 * GetNextWindow (USER.230)
2632 HWND16 WINAPI GetNextWindow16( HWND16 hwnd, WORD flag )
2634 if ((flag != GW_HWNDNEXT) && (flag != GW_HWNDPREV)) return 0;
2635 return GetWindow16( hwnd, flag );
2638 /***********************************************************************
2639 * WIN_InternalShowOwnedPopups
2641 * Internal version of ShowOwnedPopups; Wine functions should use this
2642 * to avoid interfering with application calls to ShowOwnedPopups
2643 * and to make sure the application can't prevent showing/hiding.
2645 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2649 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2651 INT totalChild=0, count=0;
2653 WND **pWnd = WIN_BuildWinArray(WIN_GetDesktop(), 0, &totalChild);
2655 if (!pWnd) return TRUE;
2658 * Show windows Lowest first, Highest last to preserve Z-Order
2660 for (count = totalChild-1 ; count >=0; count--)
2662 if (pWnd[count]->owner && (pWnd[count]->owner->hwndSelf == owner) && (pWnd[count]->dwStyle & WS_POPUP))
2666 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2667 if (pWnd[count]->flags & WIN_NEEDS_INTERNALSOP)
2670 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2672 ShowWindow(pWnd[count]->hwndSelf,SW_SHOW);
2673 pWnd[count]->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2678 if ( IsWindowVisible(pWnd[count]->hwndSelf) && /* hide only if window is visible */
2679 !( pWnd[count]->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2680 !( unmanagedOnly && (pWnd[count]->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2683 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2685 ShowWindow(pWnd[count]->hwndSelf,SW_HIDE);
2686 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2687 pWnd[count]->flags |= WIN_NEEDS_INTERNALSOP;
2692 WIN_ReleaseDesktop();
2693 WIN_ReleaseWinArray(pWnd);
2698 /*******************************************************************
2699 * ShowOwnedPopups (USER.265)
2701 void WINAPI ShowOwnedPopups16( HWND16 owner, BOOL16 fShow )
2703 ShowOwnedPopups( owner, fShow );
2707 /*******************************************************************
2708 * ShowOwnedPopups (USER32.@)
2710 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2712 UINT totalChild=0, count=0;
2714 WND **pWnd = WIN_BuildWinArray(WIN_GetDesktop(), 0, &totalChild);
2716 if (!pWnd) return TRUE;
2718 for (; count < totalChild; count++)
2720 if (pWnd[count]->owner && (pWnd[count]->owner->hwndSelf == owner) && (pWnd[count]->dwStyle & WS_POPUP))
2724 if (pWnd[count]->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2727 * In Windows, ShowOwnedPopups(TRUE) generates WM_SHOWWINDOW messages with SW_PARENTOPENING,
2728 * regardless of the state of the owner
2730 SendMessageA(pWnd[count]->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2731 pWnd[count]->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2736 if (IsWindowVisible(pWnd[count]->hwndSelf))
2739 * In Windows, ShowOwnedPopups(FALSE) generates WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2740 * regardless of the state of the owner
2742 SendMessageA(pWnd[count]->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2743 pWnd[count]->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2749 WIN_ReleaseDesktop();
2750 WIN_ReleaseWinArray(pWnd);
2755 /*******************************************************************
2756 * GetLastActivePopup (USER.287)
2758 HWND16 WINAPI GetLastActivePopup16( HWND16 hwnd )
2760 return GetLastActivePopup( hwnd );
2763 /*******************************************************************
2764 * GetLastActivePopup (USER32.@)
2766 HWND WINAPI GetLastActivePopup( HWND hwnd )
2769 WND *wndPtr =WIN_FindWndPtr(hwnd);
2770 if (!wndPtr) return hwnd;
2771 retval = wndPtr->hwndLastActive;
2772 WIN_ReleaseWndPtr(wndPtr);
2773 if ((retval != hwnd) && (!IsWindow(retval)))
2779 /*******************************************************************
2782 * Build an array of pointers to the children of a given window.
2783 * The array must be freed with WIN_ReleaseWinArray. Return NULL
2784 * when no windows are found.
2786 WND **WIN_BuildWinArray( WND *wndPtr, UINT bwaFlags, UINT* pTotal )
2788 /* Future: this function will lock all windows associated with this array */
2790 WND **list, **ppWnd;
2792 UINT count = 0, skipOwned, skipHidden;
2795 skipHidden = bwaFlags & BWA_SKIPHIDDEN;
2796 skipOwned = bwaFlags & BWA_SKIPOWNED;
2797 skipFlags = (bwaFlags & BWA_SKIPDISABLED) ? WS_DISABLED : 0;
2798 if( bwaFlags & BWA_SKIPICONIC ) skipFlags |= WS_MINIMIZE;
2800 /* First count the windows */
2803 wndPtr = WIN_GetDesktop();
2805 pWnd = WIN_LockWndPtr(wndPtr->child);
2808 if( !(pWnd->dwStyle & skipFlags) && !(skipOwned && pWnd->owner) &&
2809 (!skipHidden || (pWnd->dwStyle & WS_VISIBLE)) )
2811 WIN_UpdateWndPtr(&pWnd,pWnd->next);
2816 /* Now build the list of all windows */
2818 if ((list = (WND **)HeapAlloc( GetProcessHeap(), 0, sizeof(WND *) * (count + 1))))
2820 for (pWnd = WIN_LockWndPtr(wndPtr->child), ppWnd = list, count = 0; pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2822 if( (pWnd->dwStyle & skipFlags) || (skipOwned && pWnd->owner) );
2823 else if( !skipHidden || pWnd->dwStyle & WS_VISIBLE )
2829 WIN_ReleaseWndPtr(pWnd);
2835 if( pTotal ) *pTotal = count;
2838 /*******************************************************************
2839 * WIN_ReleaseWinArray
2841 void WIN_ReleaseWinArray(WND **wndArray)
2843 /* Future: this function will also unlock all windows associated with wndArray */
2844 HeapFree( GetProcessHeap(), 0, wndArray );
2848 /*******************************************************************
2849 * EnumWindows (USER32.@)
2851 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2853 WND **list, **ppWnd;
2855 /* We have to build a list of all windows first, to avoid */
2856 /* unpleasant side-effects, for instance if the callback */
2857 /* function changes the Z-order of the windows. */
2859 if (!(list = WIN_BuildWinArray(WIN_GetDesktop(), 0, NULL )))
2861 WIN_ReleaseDesktop();
2865 /* Now call the callback function for every window */
2867 for (ppWnd = list; *ppWnd; ppWnd++)
2869 LRESULT lpEnumFuncRetval;
2871 /* Make sure that the window still exists */
2872 if (!IsWindow((*ppWnd)->hwndSelf)) continue;
2874 /* To avoid any deadlocks, all the locks on the windows
2875 structures must be suspended before the control
2876 is passed to the application */
2877 iWndsLocks = WIN_SuspendWndsLock();
2878 lpEnumFuncRetval = lpEnumFunc( (*ppWnd)->hwndSelf, lParam);
2879 WIN_RestoreWndsLock(iWndsLocks);
2881 if (!lpEnumFuncRetval) break;
2883 WIN_ReleaseWinArray(list);
2884 WIN_ReleaseDesktop();
2889 /**********************************************************************
2890 * EnumTaskWindows (USER.225)
2892 BOOL16 WINAPI EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
2895 WND **list, **ppWnd;
2897 /* This function is the same as EnumWindows(), */
2898 /* except for an added check on the window's task. */
2900 if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
2902 WIN_ReleaseDesktop();
2906 /* Now call the callback function for every window */
2908 for (ppWnd = list; *ppWnd; ppWnd++)
2912 /* Make sure that the window still exists */
2913 if (!IsWindow((*ppWnd)->hwndSelf)) continue;
2914 if (QUEUE_GetQueueTask((*ppWnd)->hmemTaskQ) != hTask) continue;
2916 /* To avoid any deadlocks, all the locks on the windows
2917 structures must be suspended before the control
2918 is passed to the application */
2919 iWndsLocks = WIN_SuspendWndsLock();
2920 funcRetval = func( (*ppWnd)->hwndSelf, lParam );
2921 WIN_RestoreWndsLock(iWndsLocks);
2923 if (!funcRetval) break;
2925 WIN_ReleaseWinArray(list);
2926 WIN_ReleaseDesktop();
2931 /**********************************************************************
2932 * EnumThreadWindows (USER32.@)
2934 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2936 TEB *teb = THREAD_IdToTEB(id);
2938 return (BOOL16)EnumTaskWindows16(teb->htask16, (WNDENUMPROC16)func, lParam);
2942 /**********************************************************************
2943 * WIN_EnumChildWindows
2945 * Helper function for EnumChildWindows().
2947 static BOOL16 WIN_EnumChildWindows( WND **ppWnd, WNDENUMPROC func, LPARAM lParam )
2952 for ( ; *ppWnd; ppWnd++)
2956 /* Make sure that the window still exists */
2957 if (!IsWindow((*ppWnd)->hwndSelf)) continue;
2958 /* Build children list first */
2959 childList = WIN_BuildWinArray( *ppWnd, BWA_SKIPOWNED, NULL );
2961 /* To avoid any deadlocks, all the locks on the windows
2962 structures must be suspended before the control
2963 is passed to the application */
2964 iWndsLocks = WIN_SuspendWndsLock();
2965 ret = func( (*ppWnd)->hwndSelf, lParam );
2966 WIN_RestoreWndsLock(iWndsLocks);
2970 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2971 WIN_ReleaseWinArray(childList);
2973 if (!ret) return FALSE;
2979 /**********************************************************************
2980 * EnumChildWindows (USER32.@)
2982 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func,
2985 WND **list, *pParent;
2987 if (!(pParent = WIN_FindWndPtr( parent ))) return FALSE;
2988 if (!(list = WIN_BuildWinArray( pParent, BWA_SKIPOWNED, NULL )))
2990 WIN_ReleaseWndPtr(pParent);
2993 WIN_EnumChildWindows( list, func, lParam );
2994 WIN_ReleaseWinArray(list);
2995 WIN_ReleaseWndPtr(pParent);
3000 /*******************************************************************
3001 * AnyPopup (USER.52)
3003 BOOL16 WINAPI AnyPopup16(void)
3009 /*******************************************************************
3010 * AnyPopup (USER32.@)
3012 BOOL WINAPI AnyPopup(void)
3014 WND *wndPtr = WIN_LockWndPtr(pWndDesktop->child);
3019 if (wndPtr->owner && (wndPtr->dwStyle & WS_VISIBLE))
3024 WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
3028 WIN_ReleaseWndPtr(wndPtr);
3033 /*******************************************************************
3034 * FlashWindow (USER.105)
3036 BOOL16 WINAPI FlashWindow16( HWND16 hWnd, BOOL16 bInvert )
3038 return FlashWindow( hWnd, bInvert );
3042 /*******************************************************************
3043 * FlashWindow (USER32.@)
3045 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3047 WND *wndPtr = WIN_FindWndPtr(hWnd);
3049 TRACE("%04x\n", hWnd);
3051 if (!wndPtr) return FALSE;
3053 if (wndPtr->dwStyle & WS_MINIMIZE)
3055 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3057 HDC hDC = GetDC(hWnd);
3059 if (!SendMessage16( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
3060 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3062 ReleaseDC( hWnd, hDC );
3063 wndPtr->flags |= WIN_NCACTIVATED;
3067 PAINT_RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE |
3068 RDW_UPDATENOW | RDW_FRAME, 0 );
3069 wndPtr->flags &= ~WIN_NCACTIVATED;
3071 WIN_ReleaseWndPtr(wndPtr);
3077 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3078 else wparam = (hWnd == GetActiveWindow());
3080 SendMessage16( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3081 WIN_ReleaseWndPtr(wndPtr);
3087 /*******************************************************************
3088 * SetSysModalWindow (USER.188)
3090 HWND16 WINAPI SetSysModalWindow16( HWND16 hWnd )
3092 HWND hWndOldModal = hwndSysModal;
3093 hwndSysModal = hWnd;
3094 FIXME("EMPTY STUB !! SetSysModalWindow(%04x) !\n", hWnd);
3095 return hWndOldModal;
3099 /*******************************************************************
3100 * GetSysModalWindow (USER.189)
3102 HWND16 WINAPI GetSysModalWindow16(void)
3104 return hwndSysModal;
3108 /*******************************************************************
3109 * GetWindowContextHelpId (USER32.@)
3111 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3114 WND *wnd = WIN_FindWndPtr( hwnd );
3116 retval = wnd->helpContext;
3117 WIN_ReleaseWndPtr(wnd);
3122 /*******************************************************************
3123 * SetWindowContextHelpId (USER32.@)
3125 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3127 WND *wnd = WIN_FindWndPtr( hwnd );
3128 if (!wnd) return FALSE;
3129 wnd->helpContext = id;
3130 WIN_ReleaseWndPtr(wnd);
3135 /*******************************************************************
3138 * recursively find a child that contains spDragInfo->pt point
3139 * and send WM_QUERYDROPOBJECT
3141 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
3143 BOOL16 wParam, bResult = 0;
3145 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3146 WND *ptrQueryWnd = WIN_FindWndPtr(hQueryWnd),*ptrWnd;
3149 if( !ptrQueryWnd || !ptrDragInfo )
3152 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3154 GetWindowRect(hQueryWnd,&tempRect);
3156 if( !PtInRect(&tempRect,pt) ||
3157 (ptrQueryWnd->dwStyle & WS_DISABLED) )
3160 if( !(ptrQueryWnd->dwStyle & WS_MINIMIZE) )
3162 tempRect = ptrQueryWnd->rectClient;
3163 if(ptrQueryWnd->dwStyle & WS_CHILD)
3164 MapWindowPoints( ptrQueryWnd->parent->hwndSelf, 0,
3165 (LPPOINT)&tempRect, 2 );
3167 if (PtInRect( &tempRect, pt))
3171 for (ptrWnd = WIN_LockWndPtr(ptrQueryWnd->child); ptrWnd ;WIN_UpdateWndPtr(&ptrWnd,ptrWnd->next))
3173 if( ptrWnd->dwStyle & WS_VISIBLE )
3175 GetWindowRect( ptrWnd->hwndSelf, &tempRect );
3176 if (PtInRect( &tempRect, pt )) break;
3182 TRACE_(msg)("hwnd = %04x, %d %d - %d %d\n",
3183 ptrWnd->hwndSelf, ptrWnd->rectWindow.left, ptrWnd->rectWindow.top,
3184 ptrWnd->rectWindow.right, ptrWnd->rectWindow.bottom );
3185 if( !(ptrWnd->dwStyle & WS_DISABLED) )
3186 bResult = DRAG_QueryUpdate(ptrWnd->hwndSelf, spDragInfo, bNoSend);
3188 WIN_ReleaseWndPtr(ptrWnd);
3198 ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
3200 ptrDragInfo->hScope = hQueryWnd;
3202 bResult = ( bNoSend )
3203 ? ptrQueryWnd->dwExStyle & WS_EX_ACCEPTFILES
3204 : SendMessage16( hQueryWnd ,WM_QUERYDROPOBJECT ,
3205 (WPARAM16)wParam ,(LPARAM) spDragInfo );
3207 CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3210 WIN_ReleaseWndPtr(ptrQueryWnd);
3215 /*******************************************************************
3216 * DragDetect (USER.465)
3218 BOOL16 WINAPI DragDetect16( HWND16 hWnd, POINT16 pt )
3221 CONV_POINT16TO32( &pt, &pt32 );
3222 return DragDetect( hWnd, pt32 );
3225 /*******************************************************************
3226 * DragDetect (USER32.@)
3228 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3233 rect.left = pt.x - wDragWidth;
3234 rect.right = pt.x + wDragWidth;
3236 rect.top = pt.y - wDragHeight;
3237 rect.bottom = pt.y + wDragHeight;
3243 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3245 if( msg.message == WM_LBUTTONUP )
3250 if( msg.message == WM_MOUSEMOVE )
3253 tmp.x = LOWORD(msg.lParam);
3254 tmp.y = HIWORD(msg.lParam);
3255 if( !PtInRect( &rect, tmp ))
3267 /******************************************************************************
3268 * DragObject (USER.464)
3270 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3271 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3274 LPDRAGINFO16 lpDragInfo;
3276 HCURSOR16 hDragCursor=0, hOldCursor=0, hBummer=0;
3277 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3278 WND *wndPtr = WIN_FindWndPtr(hWnd);
3279 HCURSOR16 hCurrentCursor = 0;
3280 HWND16 hCurrentWnd = 0;
3282 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3283 spDragInfo = K32WOWGlobalLock16(hDragInfo);
3285 if( !lpDragInfo || !spDragInfo )
3287 WIN_ReleaseWndPtr(wndPtr);
3291 hBummer = LoadCursorA(0, IDC_BUMMERA);
3293 if( !hBummer || !wndPtr )
3295 GlobalFree16(hDragInfo);
3296 WIN_ReleaseWndPtr(wndPtr);
3302 if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
3304 GlobalFree16(hDragInfo);
3305 WIN_ReleaseWndPtr(wndPtr);
3309 if( hDragCursor == hCursor ) hDragCursor = 0;
3310 else hCursor = hDragCursor;
3312 hOldCursor = SetCursor(hDragCursor);
3315 lpDragInfo->hWnd = hWnd;
3316 lpDragInfo->hScope = 0;
3317 lpDragInfo->wFlags = wObj;
3318 lpDragInfo->hList = szList; /* near pointer! */
3319 lpDragInfo->hOfStruct = hOfStruct;
3327 do{ WaitMessage(); }
3328 while( !PeekMessageA(&msg,0,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE) );
3330 *(lpDragInfo+1) = *lpDragInfo;
3332 lpDragInfo->pt.x = msg.pt.x;
3333 lpDragInfo->pt.y = msg.pt.y;
3335 /* update DRAGINFO struct */
3336 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3338 if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
3339 hCurrentCursor = hCursor;
3342 hCurrentCursor = hBummer;
3343 lpDragInfo->hScope = 0;
3345 if( hCurrentCursor )
3346 SetCursor(hCurrentCursor);
3348 /* send WM_DRAGLOOP */
3349 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3350 (LPARAM) spDragInfo );
3351 /* send WM_DRAGSELECT or WM_DRAGMOVE */
3352 if( hCurrentWnd != lpDragInfo->hScope )
3355 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3356 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3357 HIWORD(spDragInfo)) );
3358 hCurrentWnd = lpDragInfo->hScope;
3360 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3364 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3366 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3369 ShowCursor( FALSE );
3373 SetCursor( hOldCursor );
3374 if (hDragCursor) DestroyCursor( hDragCursor );
3377 if( hCurrentCursor != hBummer )
3378 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3379 (WPARAM16)hWnd, (LPARAM)spDragInfo );
3382 GlobalFree16(hDragInfo);
3383 WIN_ReleaseWndPtr(wndPtr);
3385 return (DWORD)(msg.lParam);