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"
25 #include "stackframe.h"
26 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(win);
29 DECLARE_DEBUG_CHANNEL(msg);
31 /**********************************************************************/
33 WND_DRIVER *WND_Driver = NULL;
36 static WND *pWndDesktop = NULL;
38 static HWND hwndSysModal = 0;
40 static WORD wDragWidth = 4;
41 static WORD wDragHeight= 3;
44 static SYSLEVEL WIN_SysLevel = { CRITICAL_SECTION_INIT, 2 };
46 /***********************************************************************
49 * Locks access to all WND structures for thread safeness
51 void WIN_LockWnds( void )
53 _EnterSysLevel( &WIN_SysLevel );
56 /***********************************************************************
59 * Unlocks access to all WND structures
61 void WIN_UnlockWnds( void )
63 _LeaveSysLevel( &WIN_SysLevel );
66 /***********************************************************************
69 * Suspend the lock on WND structures.
70 * Returns the number of locks suspended
72 int WIN_SuspendWndsLock( void )
74 int isuspendedLocks = _ConfirmSysLevel( &WIN_SysLevel );
75 int count = isuspendedLocks;
78 _LeaveSysLevel( &WIN_SysLevel );
80 return isuspendedLocks;
83 /***********************************************************************
86 * Restore the suspended locks on WND structures
88 void WIN_RestoreWndsLock( int ipreviousLocks )
90 while ( ipreviousLocks-- > 0 )
91 _EnterSysLevel( &WIN_SysLevel );
94 /***********************************************************************
97 * Return a pointer to the WND structure corresponding to a HWND.
99 WND * WIN_FindWndPtr( HWND hwnd )
103 if (!hwnd || HIWORD(hwnd)) goto error2;
104 ptr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
105 /* Lock all WND structures for thread safeness*/
107 /*and increment destruction monitoring*/
110 if (ptr->dwMagic != WND_MAGIC) goto error;
111 if (ptr->hwndSelf != hwnd)
113 ERR("Can't happen: hwnd %04x self pointer is %04x\n",hwnd, ptr->hwndSelf );
116 /* returns a locked pointer */
119 /* Unlock all WND structures for thread safeness*/
121 /* and decrement destruction monitoring value */
126 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
130 /***********************************************************************
133 * Use in case the wnd ptr is not initialized with WIN_FindWndPtr
135 * Returns the locked initialisation pointer
137 WND *WIN_LockWndPtr(WND *initWndPtr)
139 if(!initWndPtr) return 0;
141 /* Lock all WND structures for thread safeness*/
143 /*and increment destruction monitoring*/
144 initWndPtr->irefCount++;
150 /***********************************************************************
153 * Release the pointer to the WND structure.
155 void WIN_ReleaseWndPtr(WND *wndPtr)
159 /*Decrement destruction monitoring value*/
161 /* Check if it's time to release the memory*/
162 if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
165 USER_HEAP_FREE( wndPtr->hwndSelf);
166 wndPtr->hwndSelf = 0;
168 else if(wndPtr->irefCount < 0)
170 /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
171 ERR("forgot a Lock on %p somewhere\n",wndPtr);
173 /*unlock all WND structures for thread safeness*/
177 /***********************************************************************
180 * Updates the value of oldPtr to newPtr.
182 void WIN_UpdateWndPtr(WND **oldPtr, WND *newPtr)
186 tmpWnd = WIN_LockWndPtr(newPtr);
187 WIN_ReleaseWndPtr(*oldPtr);
192 /***********************************************************************
195 * Dump the content of a window structure to stderr.
197 void WIN_DumpWindow( HWND hwnd )
203 if (!(ptr = WIN_FindWndPtr( hwnd )))
205 WARN("%04x is not a window handle\n", hwnd );
209 if (!GetClassNameA( hwnd, className, sizeof(className ) ))
210 strcpy( className, "#NULL#" );
212 TRACE("Window %04x (%p):\n", hwnd, ptr );
213 DPRINTF( "next=%p child=%p parent=%p owner=%p class=%p '%s'\n"
214 "inst=%04x taskQ=%04x updRgn=%04x active=%04x dce=%p idmenu=%08x\n"
215 "style=%08lx exstyle=%08lx wndproc=%08x text='%s'\n"
216 "client=%d,%d-%d,%d window=%d,%d-%d,%d"
217 "sysmenu=%04x flags=%04x props=%p vscroll=%p hscroll=%p\n",
218 ptr->next, ptr->child, ptr->parent, ptr->owner,
219 ptr->class, className, ptr->hInstance, ptr->hmemTaskQ,
220 ptr->hrgnUpdate, ptr->hwndLastActive, ptr->dce, ptr->wIDmenu,
221 ptr->dwStyle, ptr->dwExStyle, (UINT)ptr->winproc,
222 ptr->text ? debugstr_w(ptr->text) : "",
223 ptr->rectClient.left, ptr->rectClient.top, ptr->rectClient.right,
224 ptr->rectClient.bottom, ptr->rectWindow.left, ptr->rectWindow.top,
225 ptr->rectWindow.right, ptr->rectWindow.bottom, ptr->hSysMenu,
226 ptr->flags, ptr->pProp, ptr->pVScroll, ptr->pHScroll );
230 DPRINTF( "extra bytes:" );
231 for (i = 0; i < ptr->cbWndExtra; i++)
232 DPRINTF( " %02x", *((BYTE*)ptr->wExtra+i) );
236 WIN_ReleaseWndPtr(ptr);
240 /***********************************************************************
243 * Walk the windows tree and print each window on stderr.
245 void WIN_WalkWindows( HWND hwnd, int indent )
250 ptr = hwnd ? WIN_FindWndPtr( hwnd ) : WIN_GetDesktop();
254 WARN("Invalid window handle %04x\n", hwnd );
258 if (!indent) /* first time around */
259 DPRINTF( "%-16.16s %-8.8s %-6.6s %-17.17s %-8.8s %s\n",
260 "hwnd", " wndPtr", "queue", "Class Name", " Style", " WndProc"
265 DPRINTF( "%*s%04x%*s", indent, "", ptr->hwndSelf, 13-indent,"");
267 GetClassNameA( ptr->hwndSelf, className, sizeof(className) );
268 DPRINTF( "%08lx %-6.4x %-17.17s %08x %08x %.14s\n",
269 (DWORD)ptr, ptr->hmemTaskQ, className,
270 (UINT)ptr->dwStyle, (UINT)ptr->winproc,
271 ptr->text ? debugstr_w(ptr->text) : "<null>");
273 if (ptr->child) WIN_WalkWindows( ptr->child->hwndSelf, indent+1 );
274 WIN_UpdateWndPtr(&ptr,ptr->next);
278 /***********************************************************************
281 * Remove a window from the siblings linked list.
283 BOOL WIN_UnlinkWindow( HWND hwnd )
285 WND *wndPtr, **ppWnd;
288 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
289 else if(!wndPtr->parent)
291 WIN_ReleaseWndPtr(wndPtr);
295 ppWnd = &wndPtr->parent->child;
296 while (*ppWnd && *ppWnd != wndPtr) ppWnd = &(*ppWnd)->next;
299 *ppWnd = wndPtr->next;
302 WIN_ReleaseWndPtr(wndPtr);
307 /***********************************************************************
310 * Insert a window into the siblings linked list.
311 * The window is inserted after the specified window, which can also
312 * be specified as HWND_TOP or HWND_BOTTOM.
314 BOOL WIN_LinkWindow( HWND hwnd, HWND hwndInsertAfter )
316 WND *wndPtr, **ppWnd;
318 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
319 else if(!wndPtr->parent)
321 WIN_ReleaseWndPtr(wndPtr);
324 if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM))
326 ppWnd = &wndPtr->parent->child; /* Point to first sibling hwnd */
327 if (hwndInsertAfter == HWND_BOTTOM) /* Find last sibling hwnd */
328 while (*ppWnd) ppWnd = &(*ppWnd)->next;
330 else /* Normal case */
332 WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter );
335 WIN_ReleaseWndPtr(wndPtr);
338 ppWnd = &afterPtr->next;
339 WIN_ReleaseWndPtr(afterPtr);
341 wndPtr->next = *ppWnd;
343 WIN_ReleaseWndPtr(wndPtr);
348 /***********************************************************************
349 * WIN_FindWinToRepaint
351 * Find a window that needs repaint.
353 HWND WIN_FindWinToRepaint( HWND hwnd, HQUEUE16 hQueue )
358 /* Note: the desktop window never gets WM_PAINT messages
359 * The real reason why is because Windows DesktopWndProc
360 * does ValidateRgn inside WM_ERASEBKGND handler.
362 if (hwnd == GetDesktopWindow()) hwnd = 0;
364 pWnd = hwnd ? WIN_FindWndPtr(hwnd) : WIN_LockWndPtr(pWndDesktop->child);
366 for ( ; pWnd ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
368 if (!(pWnd->dwStyle & WS_VISIBLE))
370 TRACE("skipping window %04x\n",
373 else if ((pWnd->hmemTaskQ == hQueue) &&
374 (pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT)))
377 else if (pWnd->child )
378 if ((hwndRet = WIN_FindWinToRepaint( pWnd->child->hwndSelf, hQueue )) )
380 WIN_ReleaseWndPtr(pWnd);
391 hwndRet = pWnd->hwndSelf;
393 /* look among siblings if we got a transparent window */
394 while (pWnd && ((pWnd->dwExStyle & WS_EX_TRANSPARENT) ||
395 !(pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT))))
397 WIN_UpdateWndPtr(&pWnd,pWnd->next);
401 hwndRet = pWnd->hwndSelf;
402 WIN_ReleaseWndPtr(pWnd);
404 TRACE("found %04x\n",hwndRet);
409 /***********************************************************************
412 * Destroy storage associated to a window. "Internals" p.358
413 * returns a locked wndPtr->next
415 static WND* WIN_DestroyWindow( WND* wndPtr )
417 HWND hwnd = wndPtr->hwndSelf;
420 TRACE("%04x\n", wndPtr->hwndSelf );
422 /* free child windows */
423 WIN_LockWndPtr(wndPtr->child);
424 while ((pWnd = wndPtr->child))
426 wndPtr->child = WIN_DestroyWindow( pWnd );
427 WIN_ReleaseWndPtr(pWnd);
431 * Clear the update region to make sure no WM_PAINT messages will be
432 * generated for this window while processing the WM_NCDESTROY.
434 if ((wndPtr->hrgnUpdate) || (wndPtr->flags & WIN_INTERNAL_PAINT))
436 if (wndPtr->hrgnUpdate > 1)
437 DeleteObject( wndPtr->hrgnUpdate );
439 QUEUE_DecPaintCount( wndPtr->hmemTaskQ );
441 wndPtr->hrgnUpdate = 0;
445 * Send the WM_NCDESTROY to the window being destroyed.
447 SendMessageA( wndPtr->hwndSelf, WM_NCDESTROY, 0, 0);
449 /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
451 WINPOS_CheckInternalPos( wndPtr );
452 if( hwnd == GetCapture()) ReleaseCapture();
454 /* free resources associated with the window */
456 TIMER_RemoveWindowTimers( wndPtr->hwndSelf );
457 PROPERTY_RemoveWindowProps( wndPtr );
459 /* toss stale messages from the queue */
461 QUEUE_CleanupWindow( hwnd );
462 wndPtr->hmemTaskQ = 0;
464 if (!(wndPtr->dwStyle & WS_CHILD))
467 DestroyMenu( wndPtr->wIDmenu );
470 if (wndPtr->hSysMenu)
472 DestroyMenu( wndPtr->hSysMenu );
473 wndPtr->hSysMenu = 0;
475 USER_Driver.pDestroyWindow( wndPtr->hwndSelf );
476 DCE_FreeWindowDCE( wndPtr ); /* Always do this to catch orphaned DCs */
477 WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
478 CLASS_RemoveWindow( wndPtr->class );
479 wndPtr->class = NULL;
480 wndPtr->dwMagic = 0; /* Mark it as invalid */
482 WIN_UpdateWndPtr(&pWnd,wndPtr->next);
487 /***********************************************************************
488 * WIN_ResetQueueWindows
490 * Reset the queue of all the children of a given window.
491 * Return TRUE if something was done.
493 BOOL WIN_ResetQueueWindows( WND* wnd, HQUEUE16 hQueue, HQUEUE16 hNew )
497 if (hNew) /* Set a new queue */
499 for (wnd = WIN_LockWndPtr(wnd->child); (wnd);WIN_UpdateWndPtr(&wnd,wnd->next))
501 if (wnd->hmemTaskQ == hQueue)
503 wnd->hmemTaskQ = hNew;
508 ret |= WIN_ResetQueueWindows( wnd, hQueue, hNew );
512 else /* Queue is being destroyed */
516 WND *tmp = WIN_LockWndPtr(wnd->child);
521 if (tmp->hmemTaskQ == hQueue)
523 DestroyWindow( tmp->hwndSelf );
527 tmp2 = WIN_LockWndPtr(tmp->child);
528 if (tmp2 && WIN_ResetQueueWindows(tmp2,hQueue,0))
532 WIN_UpdateWndPtr(&tmp,tmp->next);
534 WIN_ReleaseWndPtr(tmp2);
536 WIN_ReleaseWndPtr(tmp);
543 /***********************************************************************
544 * WIN_CreateDesktopWindow
546 * Create the desktop window.
548 BOOL WIN_CreateDesktopWindow(void)
550 struct tagCLASS *class;
557 TRACE("Creating desktop window\n");
560 if (!WINPOS_CreateInternalPosAtom() ||
561 !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
562 &wndExtra, &winproc, &clsStyle, &dce )))
565 hwndDesktop = USER_HEAP_ALLOC( sizeof(WND) + wndExtra );
566 if (!hwndDesktop) return FALSE;
567 pWndDesktop = (WND *) USER_HEAP_LIN_ADDR( hwndDesktop );
569 pWndDesktop->pDriver = WND_Driver;
570 pWndDesktop->next = NULL;
571 pWndDesktop->child = NULL;
572 pWndDesktop->parent = NULL;
573 pWndDesktop->owner = NULL;
574 pWndDesktop->class = class;
575 pWndDesktop->dwMagic = WND_MAGIC;
576 pWndDesktop->hwndSelf = hwndDesktop;
577 pWndDesktop->hInstance = 0;
578 pWndDesktop->rectWindow.left = 0;
579 pWndDesktop->rectWindow.top = 0;
580 pWndDesktop->rectWindow.right = GetSystemMetrics(SM_CXSCREEN);
581 pWndDesktop->rectWindow.bottom = GetSystemMetrics(SM_CYSCREEN);
582 pWndDesktop->rectClient = pWndDesktop->rectWindow;
583 pWndDesktop->text = NULL;
584 pWndDesktop->hmemTaskQ = 0;
585 pWndDesktop->hrgnUpdate = 0;
586 pWndDesktop->hwndLastActive = hwndDesktop;
587 pWndDesktop->dwStyle = WS_VISIBLE | WS_CLIPCHILDREN |
589 pWndDesktop->dwExStyle = 0;
590 pWndDesktop->clsStyle = clsStyle;
591 pWndDesktop->dce = NULL;
592 pWndDesktop->pVScroll = NULL;
593 pWndDesktop->pHScroll = NULL;
594 pWndDesktop->pProp = NULL;
595 pWndDesktop->wIDmenu = 0;
596 pWndDesktop->helpContext = 0;
597 pWndDesktop->flags = 0;
598 pWndDesktop->hSysMenu = 0;
599 pWndDesktop->userdata = 0;
600 pWndDesktop->winproc = winproc;
601 pWndDesktop->cbWndExtra = wndExtra;
602 pWndDesktop->irefCount = 0;
604 if (!USER_Driver.pCreateWindow( hwndDesktop )) return FALSE;
606 SendMessageW( hwndDesktop, WM_NCCREATE, 0, 0 );
607 pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
612 /***********************************************************************
615 * Fix the coordinates - Helper for WIN_CreateWindowEx.
616 * returns default show mode in sw.
617 * Note: the feature presented as undocumented *is* in the MSDN since 1993.
619 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
621 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
622 cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
624 if (cs->style & (WS_CHILD | WS_POPUP))
626 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
627 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
629 else /* overlapped window */
633 GetStartupInfoA( &info );
635 if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
637 /* Never believe Microsoft's documentation... CreateWindowEx doc says
638 * that if an overlapped window is created with WS_VISIBLE style bit
639 * set and the x parameter is set to CW_USEDEFAULT, the system ignores
640 * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
643 * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16
644 * 2) it does not ignore the y parameter as the docs claim; instead, it
645 * uses it as second parameter to ShowWindow() unless y is either
646 * CW_USEDEFAULT or CW_USEDEFAULT16.
648 * The fact that we didn't do 2) caused bogus windows pop up when wine
649 * was running apps that were using this obscure feature. Example -
650 * calc.exe that comes with Win98 (only Win98, it's different from
651 * the one that comes with Win95 and NT)
653 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
654 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
655 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
658 if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
660 if (info.dwFlags & STARTF_USESIZE)
662 cs->cx = info.dwXSize;
663 cs->cy = info.dwYSize;
665 else /* if no other hint from the app, pick 3/4 of the screen real estate */
668 SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
669 cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
670 cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
677 /***********************************************************************
680 * Implementation of CreateWindowEx().
682 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
683 WINDOWPROCTYPE type )
686 struct tagCLASS *classPtr;
689 HWND16 hwnd, hwndLinkAfter;
690 POINT maxSize, maxPos, minTrack, maxTrack;
695 LRESULT CALLBACK (*localSend32)(HWND, UINT, WPARAM, LPARAM);
697 TRACE("%s %s %08lx %08lx %d,%d %dx%d %04x %04x %08x %p\n",
698 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszName) : debugres_a(cs->lpszName),
699 (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszClass) : debugres_a(cs->lpszClass),
700 cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
701 cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
703 TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
704 ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
706 /* Find the parent window */
710 /* Make sure parent is valid */
711 if (!IsWindow( cs->hwndParent ))
713 WARN("Bad parent %04x\n", cs->hwndParent );
716 } else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP)) {
717 WARN("No parent for child window\n" );
718 return 0; /* WS_CHILD needs a parent, but WS_POPUP doesn't */
721 /* Find the window class */
722 if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
723 &wndExtra, &winproc, &clsStyle, &dce )))
725 WARN("Bad class '%s'\n", cs->lpszClass );
729 WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
731 /* Create the window structure */
733 if (!(hwnd = USER_HEAP_ALLOC( sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
735 TRACE("out of memory\n" );
739 /* Fill the window structure */
741 wndPtr = WIN_LockWndPtr((WND *) USER_HEAP_LIN_ADDR( hwnd ));
743 wndPtr->child = NULL;
745 if ((cs->style & WS_CHILD) && cs->hwndParent)
747 wndPtr->parent = WIN_FindWndPtr( cs->hwndParent );
748 wndPtr->owner = NULL;
749 WIN_ReleaseWndPtr(wndPtr->parent);
753 wndPtr->parent = pWndDesktop;
754 if (!cs->hwndParent || (cs->hwndParent == pWndDesktop->hwndSelf))
755 wndPtr->owner = NULL;
758 WND *tmpWnd = WIN_FindWndPtr(cs->hwndParent);
759 wndPtr->owner = WIN_GetTopParentPtr(tmpWnd);
760 WIN_ReleaseWndPtr(wndPtr->owner);
761 WIN_ReleaseWndPtr(tmpWnd);
766 wndPtr->pDriver = wndPtr->parent->pDriver;
768 wndPtr->class = classPtr;
769 wndPtr->winproc = winproc;
770 wndPtr->dwMagic = WND_MAGIC;
771 wndPtr->hwndSelf = hwnd;
772 wndPtr->hInstance = cs->hInstance;
774 wndPtr->hmemTaskQ = GetFastQueue16();
775 wndPtr->hrgnUpdate = 0;
777 wndPtr->hwndLastActive = hwnd;
778 wndPtr->dwStyle = cs->style & ~WS_VISIBLE;
779 wndPtr->dwExStyle = cs->dwExStyle;
780 wndPtr->clsStyle = clsStyle;
782 wndPtr->helpContext = 0;
783 wndPtr->flags = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
784 wndPtr->pVScroll = NULL;
785 wndPtr->pHScroll = NULL;
786 wndPtr->pProp = NULL;
787 wndPtr->userdata = 0;
788 wndPtr->hSysMenu = (wndPtr->dwStyle & WS_SYSMENU)
789 ? MENU_GetSysMenu( hwnd, 0 ) : 0;
790 wndPtr->cbWndExtra = wndExtra;
791 wndPtr->irefCount = 1;
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 ))
806 cbtc.hwndInsertAfter = hwndLinkAfter;
807 ret = (type == WIN_PROC_32W) ? HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND, hwnd, (LPARAM)&cbtc)
808 : HOOK_CallHooksA(WH_CBT, HCBT_CREATEWND, hwnd, (LPARAM)&cbtc);
811 TRACE("CBT-hook returned 0\n");
812 USER_HEAP_FREE( hwnd );
813 CLASS_RemoveWindow( classPtr );
819 /* Correct the window style */
821 if (!(cs->style & WS_CHILD))
823 wndPtr->dwStyle |= WS_CLIPSIBLINGS;
824 if (!(cs->style & WS_POPUP))
826 wndPtr->dwStyle |= WS_CAPTION;
827 wndPtr->flags |= WIN_NEED_SIZE;
831 /* Get class or window DC if needed */
833 if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
834 else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
835 else wndPtr->dce = NULL;
837 /* Initialize the dimensions before sending WM_GETMINMAXINFO */
839 wndPtr->rectWindow.left = cs->x;
840 wndPtr->rectWindow.top = cs->y;
841 wndPtr->rectWindow.right = cs->x + cs->cx;
842 wndPtr->rectWindow.bottom = cs->y + cs->cy;
843 wndPtr->rectClient = wndPtr->rectWindow;
845 /* Send the WM_GETMINMAXINFO message and fix the size if needed */
847 if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
849 WINPOS_GetMinMaxInfo( wndPtr, &maxSize, &maxPos, &minTrack, &maxTrack);
850 if (maxSize.x < cs->cx) cs->cx = maxSize.x;
851 if (maxSize.y < cs->cy) cs->cy = maxSize.y;
852 if (cs->cx < minTrack.x ) cs->cx = minTrack.x;
853 if (cs->cy < minTrack.y ) cs->cy = minTrack.y;
856 if (cs->cx < 0) cs->cx = 0;
857 if (cs->cy < 0) cs->cy = 0;
859 wndPtr->rectWindow.left = cs->x;
860 wndPtr->rectWindow.top = cs->y;
861 wndPtr->rectWindow.right = cs->x + cs->cx;
862 wndPtr->rectWindow.bottom = cs->y + cs->cy;
863 wndPtr->rectClient = wndPtr->rectWindow;
865 if (!USER_Driver.pCreateWindow(wndPtr->hwndSelf))
871 /* Set the window menu */
873 if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
875 if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
878 LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
881 if (HIWORD(cs->hInstance))
882 cs->hMenu = LoadMenuA(cs->hInstance,menuName);
884 cs->hMenu = LoadMenu16(cs->hInstance,menuName);
886 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
890 else wndPtr->wIDmenu = (UINT)cs->hMenu;
892 /* Send the WM_CREATE message
893 * Perhaps we shouldn't allow width/height changes as well.
894 * See p327 in "Internals".
897 maxPos.x = wndPtr->rectWindow.left; maxPos.y = wndPtr->rectWindow.top;
899 localSend32 = (type == WIN_PROC_32W) ? SendMessageW : SendMessageA;
900 if( (*localSend32)( hwnd, WM_NCCREATE, 0, (LPARAM)cs) )
902 /* Insert the window in the linked list */
904 WIN_LinkWindow( hwnd, hwndLinkAfter );
906 WINPOS_SendNCCalcSize( hwnd, FALSE, &wndPtr->rectWindow,
907 NULL, NULL, 0, &wndPtr->rectClient );
908 OffsetRect(&wndPtr->rectWindow, maxPos.x - wndPtr->rectWindow.left,
909 maxPos.y - wndPtr->rectWindow.top);
910 if( ((*localSend32)( hwnd, WM_CREATE, 0, (LPARAM)cs )) != -1 )
912 /* Send the size messages */
914 if (!(wndPtr->flags & WIN_NEED_SIZE))
917 if (((wndPtr->rectClient.right-wndPtr->rectClient.left) <0)
918 ||((wndPtr->rectClient.bottom-wndPtr->rectClient.top)<0))
919 WARN("sending bogus WM_SIZE message 0x%08lx\n",
920 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
921 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
922 (*localSend32)( hwnd, WM_SIZE, SIZE_RESTORED,
923 MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
924 wndPtr->rectClient.bottom-wndPtr->rectClient.top));
925 (*localSend32)( hwnd, WM_MOVE, 0,
926 MAKELONG( wndPtr->rectClient.left,
927 wndPtr->rectClient.top ) );
930 /* Show the window, maximizing or minimizing if needed */
932 if (wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE))
935 UINT16 swFlag = (wndPtr->dwStyle & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
936 wndPtr->dwStyle &= ~(WS_MAXIMIZE | WS_MINIMIZE);
937 WINPOS_MinMaximize( wndPtr, swFlag, &newPos );
938 swFlag = ((wndPtr->dwStyle & WS_CHILD) || GetActiveWindow())
939 ? SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED
940 : SWP_NOZORDER | SWP_FRAMECHANGED;
941 SetWindowPos( hwnd, 0, newPos.left, newPos.top,
942 newPos.right, newPos.bottom, swFlag );
945 if( (wndPtr->dwStyle & WS_CHILD) && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
947 /* Notify the parent window only */
949 SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
950 MAKEWPARAM(WM_CREATE, wndPtr->wIDmenu), (LPARAM)hwnd );
951 if( !IsWindow(hwnd) )
958 if (cs->style & WS_VISIBLE) ShowWindow( hwnd, sw );
960 /* Call WH_SHELL hook */
962 if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
963 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, hwnd, 0 );
965 TRACE("created window %04x\n", hwnd);
969 WIN_UnlinkWindow( hwnd );
972 /* Abort window creation */
974 WARN("aborted by WM_xxCREATE!\n");
975 WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr ));
976 CLASS_RemoveWindow( classPtr );
979 WIN_ReleaseWndPtr(wndPtr);
985 /***********************************************************************
986 * CreateWindow (USER.41)
988 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
989 DWORD style, INT16 x, INT16 y, INT16 width,
990 INT16 height, HWND16 parent, HMENU16 menu,
991 HINSTANCE16 instance, LPVOID data )
993 return CreateWindowEx16( 0, className, windowName, style,
994 x, y, width, height, parent, menu, instance, data );
998 /***********************************************************************
999 * CreateWindowEx (USER.452)
1001 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
1002 LPCSTR windowName, DWORD style, INT16 x,
1003 INT16 y, INT16 width, INT16 height,
1004 HWND16 parent, HMENU16 menu,
1005 HINSTANCE16 instance, LPVOID data )
1011 /* Find the class atom */
1013 if (HIWORD(className))
1015 if (!(classAtom = GlobalFindAtomA( className )))
1017 ERR( "bad class name %s\n", debugres_a(className) );
1023 classAtom = LOWORD(className);
1024 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1026 ERR( "bad atom %x\n", classAtom);
1032 /* Fix the coordinates */
1034 cs.x = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
1035 cs.y = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
1036 cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
1037 cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
1039 /* Create the window */
1041 cs.lpCreateParams = data;
1042 cs.hInstance = (HINSTANCE)instance;
1043 cs.hMenu = (HMENU)menu;
1044 cs.hwndParent = (HWND)parent;
1046 cs.lpszName = windowName;
1047 cs.lpszClass = className;
1048 cs.dwExStyle = exStyle;
1050 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 );
1054 /***********************************************************************
1055 * CreateWindowExA (USER32.@)
1057 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1058 LPCSTR windowName, DWORD style, INT x,
1059 INT y, INT width, INT height,
1060 HWND parent, HMENU menu,
1061 HINSTANCE instance, LPVOID data )
1068 instance=GetModuleHandleA(NULL);
1070 if(exStyle & WS_EX_MDICHILD)
1071 return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1073 /* Find the class atom */
1075 if (HIWORD(className))
1077 if (!(classAtom = GlobalFindAtomA( className )))
1079 ERR( "bad class name %s\n", debugres_a(className) );
1085 classAtom = LOWORD(className);
1086 if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
1088 ERR( "bad atom %x\n", classAtom);
1094 /* Create the window */
1096 cs.lpCreateParams = data;
1097 cs.hInstance = instance;
1099 cs.hwndParent = parent;
1105 cs.lpszName = windowName;
1106 cs.lpszClass = className;
1107 cs.dwExStyle = exStyle;
1109 return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
1113 /***********************************************************************
1114 * CreateWindowExW (USER32.@)
1116 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1117 LPCWSTR windowName, DWORD style, INT x,
1118 INT y, INT width, INT height,
1119 HWND parent, HMENU menu,
1120 HINSTANCE instance, LPVOID data )
1127 instance=GetModuleHandleA(NULL);
1129 if(exStyle & WS_EX_MDICHILD)
1130 return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
1132 /* Find the class atom */
1134 if (HIWORD(className))
1136 if (!(classAtom = GlobalFindAtomW( className )))
1138 ERR( "bad class name %s\n", debugres_w(className) );
1144 classAtom = LOWORD(className);
1145 if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
1147 ERR( "bad atom %x\n", classAtom);
1153 /* Create the window */
1155 cs.lpCreateParams = data;
1156 cs.hInstance = instance;
1158 cs.hwndParent = parent;
1164 cs.lpszName = windowName;
1165 cs.lpszClass = className;
1166 cs.dwExStyle = exStyle;
1168 /* Note: we rely on the fact that CREATESTRUCTA and */
1169 /* CREATESTRUCTW have the same layout. */
1170 return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
1173 /***********************************************************************
1174 * WIN_SendDestroyMsg
1176 static void WIN_SendDestroyMsg( WND* pWnd )
1178 if( CARET_GetHwnd() == pWnd->hwndSelf ) DestroyCaret();
1179 USER_Driver.pResetSelectionOwner( pWnd, TRUE );
1182 * Send the WM_DESTROY to the window.
1184 SendMessageA( pWnd->hwndSelf, WM_DESTROY, 0, 0);
1187 * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1188 * make sure that the window still exists when we come back.
1190 if (IsWindow(pWnd->hwndSelf))
1192 HWND* pWndArray = NULL;
1197 * Now, if the window has kids, we have to send WM_DESTROY messages
1198 * recursively to it's kids. It seems that those calls can also
1199 * trigger re-entrant calls to DestroyWindow for the kids so we must
1200 * protect against corruption of the list of siblings. We first build
1201 * a list of HWNDs representing all the kids.
1203 pChild = WIN_LockWndPtr(pWnd->child);
1207 WIN_UpdateWndPtr(&pChild,pChild->next);
1211 * If there are no kids, we're done.
1216 pWndArray = HeapAlloc(GetProcessHeap(), 0, nKidCount*sizeof(HWND));
1221 if (pWndArray==NULL)
1225 * Now, enumerate all the kids in a list, since we wait to make the SendMessage
1226 * call, our linked list of siblings should be safe.
1229 pChild = WIN_LockWndPtr(pWnd->child);
1232 pWndArray[nKidCount] = pChild->hwndSelf;
1234 WIN_UpdateWndPtr(&pChild,pChild->next);
1238 * Now that we have a list, go through that list again and send the destroy
1239 * message to those windows. We are using the HWND to retrieve the
1240 * WND pointer so we are effectively checking that all the kid windows are
1241 * still valid before sending the message.
1245 pChild = WIN_FindWndPtr(pWndArray[--nKidCount]);
1249 WIN_SendDestroyMsg( pChild );
1250 WIN_ReleaseWndPtr(pChild);
1257 HeapFree(GetProcessHeap(), 0, pWndArray);
1260 WARN("\tdestroyed itself while in WM_DESTROY!\n");
1264 /***********************************************************************
1265 * DestroyWindow (USER.53)
1267 BOOL16 WINAPI DestroyWindow16( HWND16 hwnd )
1269 return DestroyWindow(hwnd);
1273 /***********************************************************************
1274 * DestroyWindow (USER32.@)
1276 BOOL WINAPI DestroyWindow( HWND hwnd )
1281 BOOL bFocusSet = FALSE;
1283 TRACE("(%04x)\n", hwnd);
1285 /* Initialization */
1287 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1288 if (wndPtr == pWndDesktop)
1290 retvalue = FALSE; /* Can't destroy desktop */
1294 /* Look whether the focus is within the tree of windows we will
1298 while (h && (GetWindowLongA(h,GWL_STYLE) & WS_CHILD))
1302 SetFocus(GetParent(h));
1308 /* If the focus is on the window we will destroy and it has no parent,
1309 * set the focus to 0.
1311 if (! bFocusSet && (h == hwnd))
1313 if (!(GetWindowLongA(h,GWL_STYLE) & WS_CHILD))
1319 if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, hwnd, 0L) )
1325 if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
1327 HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, hwnd, 0L );
1328 /* FIXME: clean up palette - see "Internals" p.352 */
1331 if( !QUEUE_IsExitingQueue(wndPtr->hmemTaskQ) )
1332 if( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
1334 /* Notify the parent window only */
1335 SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
1336 MAKEWPARAM(WM_DESTROY, wndPtr->wIDmenu), (LPARAM)hwnd );
1337 if( !IsWindow(hwnd) )
1344 USER_Driver.pResetSelectionOwner( wndPtr, FALSE ); /* before the window is unmapped */
1346 /* Hide the window */
1348 if (wndPtr->dwStyle & WS_VISIBLE)
1350 ShowWindow( hwnd, SW_HIDE );
1351 if (!IsWindow(hwnd))
1358 /* Recursively destroy owned windows */
1360 if( !(wndPtr->dwStyle & WS_CHILD) )
1364 WND *siblingPtr = WIN_LockWndPtr(wndPtr->parent->child); /* First sibling */
1367 if (siblingPtr->owner == wndPtr)
1369 if (siblingPtr->hmemTaskQ == wndPtr->hmemTaskQ)
1372 siblingPtr->owner = NULL;
1374 WIN_UpdateWndPtr(&siblingPtr,siblingPtr->next);
1378 DestroyWindow( siblingPtr->hwndSelf );
1379 WIN_ReleaseWndPtr(siblingPtr);
1384 WINPOS_ActivateOtherWindow(wndPtr);
1386 if( wndPtr->owner &&
1387 wndPtr->owner->hwndLastActive == wndPtr->hwndSelf )
1388 wndPtr->owner->hwndLastActive = wndPtr->owner->hwndSelf;
1391 /* Send destroy messages */
1393 WIN_SendDestroyMsg( wndPtr );
1394 if (!IsWindow(hwnd))
1400 /* Unlink now so we won't bother with the children later on */
1402 if( wndPtr->parent ) WIN_UnlinkWindow(hwnd);
1404 /* Destroy the window storage */
1406 WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr ));
1409 WIN_ReleaseWndPtr(wndPtr);
1414 /***********************************************************************
1415 * CloseWindow (USER.43)
1417 BOOL16 WINAPI CloseWindow16( HWND16 hwnd )
1419 return CloseWindow( hwnd );
1423 /***********************************************************************
1424 * CloseWindow (USER32.@)
1426 BOOL WINAPI CloseWindow( HWND hwnd )
1428 WND * wndPtr = WIN_FindWndPtr( hwnd );
1431 if (!wndPtr || (wndPtr->dwStyle & WS_CHILD))
1436 ShowWindow( hwnd, SW_MINIMIZE );
1439 WIN_ReleaseWndPtr(wndPtr);
1445 /***********************************************************************
1446 * OpenIcon (USER.44)
1448 BOOL16 WINAPI OpenIcon16( HWND16 hwnd )
1450 return OpenIcon( hwnd );
1454 /***********************************************************************
1455 * OpenIcon (USER32.@)
1457 BOOL WINAPI OpenIcon( HWND hwnd )
1459 if (!IsIconic( hwnd )) return FALSE;
1460 ShowWindow( hwnd, SW_SHOWNORMAL );
1465 /***********************************************************************
1468 * Implementation of FindWindow() and FindWindowEx().
1470 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className,
1478 if (!(pWnd = WIN_FindWndPtr( child ))) return 0;
1481 if (!pWnd->parent || (pWnd->parent->hwndSelf != parent))
1487 else if (pWnd->parent != pWndDesktop)
1492 WIN_UpdateWndPtr(&pWnd,pWnd->next);
1496 if (!(pWnd = parent ? WIN_FindWndPtr(parent) : WIN_LockWndPtr(pWndDesktop)))
1501 WIN_UpdateWndPtr(&pWnd,pWnd->child);
1509 for ( ; pWnd ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
1511 if (className && (GetClassWord(pWnd->hwndSelf, GCW_ATOM) != className))
1512 continue; /* Not the right class */
1514 /* Now check the title */
1518 retvalue = pWnd->hwndSelf;
1521 if (pWnd->text && !strcmpW( pWnd->text, title ))
1523 retvalue = pWnd->hwndSelf;
1528 /* In this case we need to check whether other processes
1529 own a window with the given paramters on the Desktop,
1530 but we don't, so let's at least warn about it */
1531 FIXME("Returning 0 without checking other processes\n");
1533 WIN_ReleaseWndPtr(pWnd);
1539 /***********************************************************************
1540 * FindWindow (USER.50)
1542 HWND16 WINAPI FindWindow16( LPCSTR className, LPCSTR title )
1544 return FindWindowA( className, title );
1548 /***********************************************************************
1549 * FindWindowEx (USER.427)
1551 HWND16 WINAPI FindWindowEx16( HWND16 parent, HWND16 child, LPCSTR className, LPCSTR title )
1553 return FindWindowExA( parent, child, className, title );
1557 /***********************************************************************
1558 * FindWindowA (USER32.@)
1560 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1562 HWND ret = FindWindowExA( 0, 0, className, title );
1563 if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1568 /***********************************************************************
1569 * FindWindowExA (USER32.@)
1571 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1572 LPCSTR className, LPCSTR title )
1580 /* If the atom doesn't exist, then no class */
1581 /* with this name exists either. */
1582 if (!(atom = GlobalFindAtomA( className )))
1584 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1589 buffer = HEAP_strdupAtoW( GetProcessHeap(), 0, title );
1590 hwnd = WIN_FindWindow( parent, child, atom, buffer );
1591 HeapFree( GetProcessHeap(), 0, buffer );
1596 /***********************************************************************
1597 * FindWindowExW (USER32.@)
1599 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1600 LPCWSTR className, LPCWSTR title )
1606 /* If the atom doesn't exist, then no class */
1607 /* with this name exists either. */
1608 if (!(atom = GlobalFindAtomW( className )))
1610 SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1614 return WIN_FindWindow( parent, child, atom, title );
1618 /***********************************************************************
1619 * FindWindowW (USER32.@)
1621 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1623 return FindWindowExW( 0, 0, className, title );
1627 /**********************************************************************
1629 * returns a locked pointer
1631 WND *WIN_GetDesktop(void)
1633 return WIN_LockWndPtr(pWndDesktop);
1635 /**********************************************************************
1636 * WIN_ReleaseDesktop
1637 * unlock the desktop pointer
1639 void WIN_ReleaseDesktop(void)
1641 WIN_ReleaseWndPtr(pWndDesktop);
1645 /**********************************************************************
1646 * GetDesktopWindow (USER.286)
1648 HWND16 WINAPI GetDesktopWindow16(void)
1650 return (HWND16)pWndDesktop->hwndSelf;
1654 /**********************************************************************
1655 * GetDesktopWindow (USER32.@)
1657 HWND WINAPI GetDesktopWindow(void)
1659 if (pWndDesktop) return pWndDesktop->hwndSelf;
1660 ERR( "You need the -desktop option when running with native USER\n" );
1666 /**********************************************************************
1667 * GetDesktopHwnd (USER.278)
1669 * Exactly the same thing as GetDesktopWindow(), but not documented.
1670 * Don't ask me why...
1672 HWND16 WINAPI GetDesktopHwnd16(void)
1674 return (HWND16)pWndDesktop->hwndSelf;
1678 /*******************************************************************
1679 * EnableWindow (USER.34)
1681 BOOL16 WINAPI EnableWindow16( HWND16 hwnd, BOOL16 enable )
1683 return EnableWindow( hwnd, enable );
1687 /*******************************************************************
1688 * EnableWindow (USER32.@)
1690 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1695 TRACE("( %x, %d )\n", hwnd, enable);
1697 if (USER_Driver.pEnableWindow)
1698 return USER_Driver.pEnableWindow( hwnd, enable );
1700 if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1702 retvalue = ((wndPtr->dwStyle & WS_DISABLED) != 0);
1704 if (enable && (wndPtr->dwStyle & WS_DISABLED))
1706 wndPtr->dwStyle &= ~WS_DISABLED; /* Enable window */
1707 SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1709 else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
1711 SendMessageA( wndPtr->hwndSelf, WM_CANCELMODE, 0, 0);
1713 wndPtr->dwStyle |= WS_DISABLED; /* Disable window */
1715 if (hwnd == GetFocus())
1716 SetFocus( 0 ); /* A disabled window can't have the focus */
1718 if (hwnd == GetCapture())
1719 ReleaseCapture(); /* A disabled window can't capture the mouse */
1721 SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1723 WIN_ReleaseWndPtr(wndPtr);
1728 /***********************************************************************
1729 * IsWindowEnabled (USER.35)
1731 BOOL16 WINAPI IsWindowEnabled16(HWND16 hWnd)
1733 return IsWindowEnabled(hWnd);
1737 /***********************************************************************
1738 * IsWindowEnabled (USER32.@)
1740 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1745 if (!(wndPtr = WIN_FindWndPtr(hWnd))) return FALSE;
1746 retvalue = !(wndPtr->dwStyle & WS_DISABLED);
1747 WIN_ReleaseWndPtr(wndPtr);
1753 /***********************************************************************
1754 * IsWindowUnicode (USER32.@)
1756 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1761 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1762 retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1763 WIN_ReleaseWndPtr(wndPtr);
1768 /**********************************************************************
1769 * GetWindowWord (USER.133)
1771 WORD WINAPI GetWindowWord16( HWND16 hwnd, INT16 offset )
1773 return GetWindowWord( hwnd, offset );
1777 /**********************************************************************
1778 * GetWindowWord (USER32.@)
1780 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1783 WND * wndPtr = WIN_FindWndPtr( hwnd );
1784 if (!wndPtr) return 0;
1787 if (offset + sizeof(WORD) > wndPtr->cbWndExtra)
1789 WARN("Invalid offset %d\n", offset );
1793 retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1799 if (HIWORD(wndPtr->wIDmenu))
1800 WARN("GWW_ID: discards high bits of 0x%08x!\n",
1802 retvalue = (WORD)wndPtr->wIDmenu;
1804 case GWW_HWNDPARENT:
1805 retvalue = GetParent(hwnd);
1808 if (HIWORD(wndPtr->hInstance))
1809 WARN("GWW_HINSTANCE: discards high bits of 0x%08x!\n",
1811 retvalue = (WORD)wndPtr->hInstance;
1814 WARN("Invalid offset %d\n", offset );
1819 WIN_ReleaseWndPtr(wndPtr);
1823 /**********************************************************************
1824 * SetWindowWord (USER.134)
1826 WORD WINAPI SetWindowWord16( HWND16 hwnd, INT16 offset, WORD newval )
1828 return SetWindowWord( hwnd, offset, newval );
1832 /**********************************************************************
1833 * SetWindowWord (USER32.@)
1835 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1838 WND * wndPtr = WIN_FindWndPtr( hwnd );
1839 if (!wndPtr) return 0;
1842 if (offset + sizeof(WORD) > wndPtr->cbWndExtra)
1844 WARN("Invalid offset %d\n", offset );
1848 ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1852 case GWW_ID: ptr = (WORD *)&wndPtr->wIDmenu; break;
1853 case GWW_HINSTANCE: ptr = (WORD *)&wndPtr->hInstance; break;
1854 case GWW_HWNDPARENT: retval = SetParent( hwnd, newval );
1857 WARN("Invalid offset %d\n", offset );
1864 WIN_ReleaseWndPtr(wndPtr);
1869 /**********************************************************************
1872 * Helper function for GetWindowLong().
1874 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1877 WND * wndPtr = WIN_FindWndPtr( hwnd );
1878 if (!wndPtr) return 0;
1881 if (offset + sizeof(LONG) > wndPtr->cbWndExtra)
1883 WARN("Invalid offset %d\n", offset );
1887 retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1888 /* Special case for dialog window procedure */
1889 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1891 retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1898 case GWL_USERDATA: retvalue = wndPtr->userdata;
1900 case GWL_STYLE: retvalue = wndPtr->dwStyle;
1902 case GWL_EXSTYLE: retvalue = wndPtr->dwExStyle;
1904 case GWL_ID: retvalue = (LONG)wndPtr->wIDmenu;
1906 case GWL_WNDPROC: retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc,
1909 case GWL_HWNDPARENT: retvalue = GetParent(hwnd);
1911 case GWL_HINSTANCE: retvalue = wndPtr->hInstance;
1914 WARN("Unknown offset %d\n", offset );
1918 WIN_ReleaseWndPtr(wndPtr);
1923 /**********************************************************************
1926 * Helper function for SetWindowLong().
1928 * 0 is the failure code. However, in the case of failure SetLastError
1929 * must be set to distinguish between a 0 return value and a failure.
1931 * FIXME: The error values for SetLastError may not be right. Can
1932 * someone check with the real thing?
1934 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1935 WINDOWPROCTYPE type )
1938 WND * wndPtr = WIN_FindWndPtr( hwnd );
1941 TRACE("%x=%p %x %lx %x\n",hwnd, wndPtr, offset, newval, type);
1945 /* Is this the right error? */
1946 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1952 if (offset + sizeof(LONG) > wndPtr->cbWndExtra)
1954 WARN("Invalid offset %d\n", offset );
1956 /* Is this the right error? */
1957 SetLastError( ERROR_OUTOFMEMORY );
1962 ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1963 /* Special case for dialog window procedure */
1964 if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1966 retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1967 WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
1968 type, WIN_PROC_WINDOW );
1975 ptr = (DWORD*)&wndPtr->wIDmenu;
1978 retval = SetWindowWord( hwnd, offset, newval );
1981 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
1982 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
1983 type, WIN_PROC_WINDOW );
1986 style.styleOld = wndPtr->dwStyle;
1987 style.styleNew = newval;
1988 if (wndPtr->flags & WIN_ISWIN32)
1989 SendMessageA(hwnd,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style);
1990 wndPtr->dwStyle = style.styleNew;
1991 if (wndPtr->flags & WIN_ISWIN32)
1992 SendMessageA(hwnd,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style);
1993 retval = style.styleOld;
1997 ptr = &wndPtr->userdata;
2000 style.styleOld = wndPtr->dwExStyle;
2001 style.styleNew = newval;
2002 if (wndPtr->flags & WIN_ISWIN32)
2003 SendMessageA(hwnd,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style);
2004 wndPtr->dwExStyle = newval;
2005 if (wndPtr->flags & WIN_ISWIN32)
2006 SendMessageA(hwnd,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style);
2007 retval = style.styleOld;
2011 WARN("Invalid offset %d\n", offset );
2013 /* Don't think this is right error but it should do */
2014 SetLastError( ERROR_OUTOFMEMORY );
2022 WIN_ReleaseWndPtr(wndPtr);
2027 /**********************************************************************
2028 * GetWindowLong (USER.135)
2030 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2032 return WIN_GetWindowLong( (HWND)hwnd, offset, WIN_PROC_16 );
2036 /**********************************************************************
2037 * GetWindowLongA (USER32.@)
2039 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2041 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2045 /**********************************************************************
2046 * GetWindowLongW (USER32.@)
2048 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2050 return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2054 /**********************************************************************
2055 * SetWindowLong (USER.136)
2057 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2059 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_16 );
2063 /**********************************************************************
2064 * SetWindowLongA (USER32.@)
2066 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2068 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2072 /**********************************************************************
2073 * SetWindowLongW (USER32.@) Set window attribute
2075 * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2076 * value in a window's extra memory.
2078 * The _hwnd_ parameter specifies the window. is the handle to a
2079 * window that has extra memory. The _newval_ parameter contains the
2080 * new attribute or extra memory value. If positive, the _offset_
2081 * parameter is the byte-addressed location in the window's extra
2082 * memory to set. If negative, _offset_ specifies the window
2083 * attribute to set, and should be one of the following values:
2085 * GWL_EXSTYLE The window's extended window style
2087 * GWL_STYLE The window's window style.
2089 * GWL_WNDPROC Pointer to the window's window procedure.
2091 * GWL_HINSTANCE The window's pplication instance handle.
2093 * GWL_ID The window's identifier.
2095 * GWL_USERDATA The window's user-specified data.
2097 * If the window is a dialog box, the _offset_ parameter can be one of
2098 * the following values:
2100 * DWL_DLGPROC The address of the window's dialog box procedure.
2102 * DWL_MSGRESULT The return value of a message
2103 * that the dialog box procedure processed.
2105 * DWL_USER Application specific information.
2109 * If successful, returns the previous value located at _offset_. Otherwise,
2114 * Extra memory for a window class is specified by a nonzero cbWndExtra
2115 * parameter of the WNDCLASS structure passed to RegisterClass() at the
2116 * time of class creation.
2118 * Using GWL_WNDPROC to set a new window procedure effectively creates
2119 * a window subclass. Use CallWindowProc() in the new windows procedure
2120 * to pass messages to the superclass's window procedure.
2122 * The user data is reserved for use by the application which created
2125 * Do not use GWL_STYLE to change the window's WS_DISABLE style;
2126 * instead, call the EnableWindow() function to change the window's
2129 * Do not use GWL_HWNDPARENT to reset the window's parent, use
2130 * SetParent() instead.
2133 * When offset is GWL_STYLE and the calling app's ver is 4.0,
2134 * it sends WM_STYLECHANGING before changing the settings
2135 * and WM_STYLECHANGED afterwards.
2136 * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2140 * GWL_STYLE does not dispatch WM_STYLE... messages.
2147 LONG WINAPI SetWindowLongW(
2148 HWND hwnd, /* [in] window to alter */
2149 INT offset, /* [in] offset, in bytes, of location to alter */
2150 LONG newval /* [in] new value of location */
2152 return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2156 /*******************************************************************
2157 * GetWindowText (USER.36)
2159 INT16 WINAPI GetWindowText16( HWND16 hwnd, SEGPTR lpString, INT16 nMaxCount )
2161 return (INT16)SendMessage16(hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
2165 /*******************************************************************
2166 * GetWindowTextA (USER32.@)
2168 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2170 return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount,
2174 /*******************************************************************
2175 * InternalGetWindowText (USER32.@)
2177 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2179 FIXME("(0x%08x,%p,0x%x),stub!\n",hwnd,lpString,nMaxCount);
2180 return GetWindowTextW(hwnd,lpString,nMaxCount);
2184 /*******************************************************************
2185 * GetWindowTextW (USER32.@)
2187 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2189 return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount,
2194 /*******************************************************************
2195 * SetWindowText (USER.37)
2197 BOOL16 WINAPI SetWindowText16( HWND16 hwnd, SEGPTR lpString )
2199 return (BOOL16)SendMessage16( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2203 /*******************************************************************
2204 * SetWindowText (USER32.@)
2206 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2208 return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2212 /*******************************************************************
2213 * SetWindowTextW (USER32.@)
2215 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2217 return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2221 /*******************************************************************
2222 * GetWindowTextLength (USER.38)
2224 INT16 WINAPI GetWindowTextLength16( HWND16 hwnd )
2226 return (INT16)SendMessage16( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2230 /*******************************************************************
2231 * GetWindowTextLengthA (USER32.@)
2233 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2235 return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2238 /*******************************************************************
2239 * GetWindowTextLengthW (USER32.@)
2241 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2243 return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2247 /*******************************************************************
2248 * IsWindow (USER.47)
2250 BOOL16 WINAPI IsWindow16( HWND16 hwnd )
2252 CURRENT_STACK16->es = USER_HeapSel;
2253 return IsWindow( hwnd );
2257 /*******************************************************************
2258 * IsWindow (USER32.@)
2260 BOOL WINAPI IsWindow( HWND hwnd )
2265 if(!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
2266 retvalue = (wndPtr->dwMagic == WND_MAGIC);
2267 WIN_ReleaseWndPtr(wndPtr);
2273 /*****************************************************************
2274 * GetParent (USER.46)
2276 HWND16 WINAPI GetParent16( HWND16 hwnd )
2278 return (HWND16)GetParent( hwnd );
2282 /*****************************************************************
2283 * GetParent (USER32.@)
2285 HWND WINAPI GetParent( HWND hwnd )
2290 if(!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2291 if ((!(wndPtr->dwStyle & (WS_POPUP|WS_CHILD))))
2294 WIN_UpdateWndPtr(&wndPtr,((wndPtr->dwStyle & WS_CHILD) ? wndPtr->parent : wndPtr->owner));
2296 retvalue = wndPtr->hwndSelf;
2299 WIN_ReleaseWndPtr(wndPtr);
2304 /*****************************************************************
2307 * Get the top-level parent for a child window.
2308 * returns a locked pointer
2310 WND* WIN_GetTopParentPtr( WND* pWnd )
2312 WND *tmpWnd = WIN_LockWndPtr(pWnd);
2314 while( tmpWnd && (tmpWnd->dwStyle & WS_CHILD))
2316 WIN_UpdateWndPtr(&tmpWnd,tmpWnd->parent);
2321 /*****************************************************************
2324 * Get the top-level parent for a child window.
2326 HWND WIN_GetTopParent( HWND hwnd )
2329 WND *tmpPtr = WIN_FindWndPtr(hwnd);
2330 WND *wndPtr = WIN_GetTopParentPtr (tmpPtr );
2332 retvalue = wndPtr ? wndPtr->hwndSelf : 0;
2333 WIN_ReleaseWndPtr(tmpPtr);
2334 WIN_ReleaseWndPtr(wndPtr);
2339 /*****************************************************************
2340 * SetParent (USER.233)
2342 HWND16 WINAPI SetParent16( HWND16 hwndChild, HWND16 hwndNewParent )
2344 return SetParent( hwndChild, hwndNewParent );
2348 /*****************************************************************
2349 * SetParent (USER32.@)
2351 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2358 if (hwnd == GetDesktopWindow()) /* sanity check */
2360 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2364 if (USER_Driver.pSetParent)
2365 return USER_Driver.pSetParent( hwnd, parent );
2367 if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2369 dwStyle = wndPtr->dwStyle;
2371 if (!parent) parent = GetDesktopWindow();
2373 if (!(pWndParent = WIN_FindWndPtr(parent)))
2375 WIN_ReleaseWndPtr( wndPtr );
2379 /* Windows hides the window first, then shows it again
2380 * including the WM_SHOWWINDOW messages and all */
2381 if (dwStyle & WS_VISIBLE) ShowWindow( hwnd, SW_HIDE );
2383 retvalue = wndPtr->parent->hwndSelf; /* old parent */
2384 if (pWndParent != wndPtr->parent)
2386 WIN_UnlinkWindow(wndPtr->hwndSelf);
2387 wndPtr->parent = pWndParent;
2389 if (parent != GetDesktopWindow()) /* a child window */
2391 if( !( wndPtr->dwStyle & WS_CHILD ) )
2393 if( wndPtr->wIDmenu != 0)
2395 DestroyMenu( (HMENU) wndPtr->wIDmenu );
2396 wndPtr->wIDmenu = 0;
2400 WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP);
2402 WIN_ReleaseWndPtr( pWndParent );
2403 WIN_ReleaseWndPtr( wndPtr );
2405 /* SetParent additionally needs to make hwnd the topmost window
2406 in the x-order and send the expected WM_WINDOWPOSCHANGING and
2407 WM_WINDOWPOSCHANGED notification messages.
2409 SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2410 SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|
2411 ((dwStyle & WS_VISIBLE)?SWP_SHOWWINDOW:0));
2412 /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2413 * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2418 /*******************************************************************
2421 BOOL16 WINAPI IsChild16( HWND16 parent, HWND16 child )
2423 return IsChild(parent,child);
2427 /*******************************************************************
2428 * IsChild (USER32.@)
2430 BOOL WINAPI IsChild( HWND parent, HWND child )
2432 WND * wndPtr = WIN_FindWndPtr( child );
2433 while (wndPtr && wndPtr->parent)
2435 WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
2436 if (wndPtr->hwndSelf == GetDesktopWindow()) break;
2437 if (wndPtr->hwndSelf == parent)
2439 WIN_ReleaseWndPtr(wndPtr);
2443 WIN_ReleaseWndPtr(wndPtr);
2448 /***********************************************************************
2449 * IsWindowVisible (USER.49)
2451 BOOL16 WINAPI IsWindowVisible16( HWND16 hwnd )
2453 return IsWindowVisible(hwnd);
2457 /***********************************************************************
2458 * IsWindowVisible (USER32.@)
2460 BOOL WINAPI IsWindowVisible( HWND hwnd )
2463 WND *wndPtr = WIN_FindWndPtr( hwnd );
2464 while (wndPtr && wndPtr->parent)
2466 if (!(wndPtr->dwStyle & WS_VISIBLE))
2468 WIN_ReleaseWndPtr(wndPtr);
2471 WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
2473 retval = (wndPtr && (wndPtr->dwStyle & WS_VISIBLE));
2474 WIN_ReleaseWndPtr(wndPtr);
2479 /***********************************************************************
2480 * WIN_IsWindowDrawable
2482 * hwnd is drawable when it is visible, all parents are not
2483 * minimized, and it is itself not minimized unless we are
2484 * trying to draw its default class icon.
2486 BOOL WIN_IsWindowDrawable( WND* wnd, BOOL icon )
2488 if (!(wnd->dwStyle & WS_VISIBLE)) return FALSE;
2489 if ((wnd->dwStyle & WS_MINIMIZE) &&
2490 icon && GetClassLongA( wnd->hwndSelf, GCL_HICON )) return FALSE;
2491 for(wnd = wnd->parent; wnd; wnd = wnd->parent)
2492 if( wnd->dwStyle & WS_MINIMIZE ||
2493 !(wnd->dwStyle & WS_VISIBLE) ) break;
2494 return (wnd == NULL);
2498 /*******************************************************************
2499 * GetTopWindow (USER.229)
2501 HWND16 WINAPI GetTopWindow16( HWND16 hwnd )
2503 return GetTopWindow(hwnd);
2507 /*******************************************************************
2508 * GetTopWindow (USER32.@)
2510 HWND WINAPI GetTopWindow( HWND hwnd )
2513 WND * wndPtr = (hwnd) ?
2514 WIN_FindWndPtr( hwnd ) : WIN_GetDesktop();
2516 if (wndPtr && wndPtr->child)
2517 retval = wndPtr->child->hwndSelf;
2519 WIN_ReleaseWndPtr(wndPtr);
2524 /*******************************************************************
2525 * GetWindow (USER.262)
2527 HWND16 WINAPI GetWindow16( HWND16 hwnd, WORD rel )
2529 return GetWindow( hwnd,rel );
2533 /*******************************************************************
2534 * GetWindow (USER32.@)
2536 HWND WINAPI GetWindow( HWND hwnd, WORD rel )
2540 WND * wndPtr = WIN_FindWndPtr( hwnd );
2541 if (!wndPtr) return 0;
2545 retval = wndPtr->parent ? wndPtr->parent->child->hwndSelf : 0;
2549 if (!wndPtr->parent)
2551 retval = 0; /* Desktop window */
2554 while (wndPtr->next)
2556 WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
2558 retval = wndPtr->hwndSelf;
2562 retval = wndPtr->next ? wndPtr->next->hwndSelf : 0;
2566 if (!wndPtr->parent)
2568 retval = 0; /* Desktop window */
2571 WIN_UpdateWndPtr(&wndPtr,wndPtr->parent->child); /* First sibling */
2572 if (wndPtr->hwndSelf == hwnd)
2574 retval = 0; /* First in list */
2577 while (wndPtr->next)
2579 if (wndPtr->next->hwndSelf == hwnd)
2581 retval = wndPtr->hwndSelf;
2584 WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
2590 retval = wndPtr->owner ? wndPtr->owner->hwndSelf : 0;
2594 retval = wndPtr->child ? wndPtr->child->hwndSelf : 0;
2599 WIN_ReleaseWndPtr(wndPtr);
2604 /*******************************************************************
2605 * GetNextWindow (USER.230)
2607 HWND16 WINAPI GetNextWindow16( HWND16 hwnd, WORD flag )
2609 if ((flag != GW_HWNDNEXT) && (flag != GW_HWNDPREV)) return 0;
2610 return GetWindow16( hwnd, flag );
2613 /***********************************************************************
2614 * WIN_InternalShowOwnedPopups
2616 * Internal version of ShowOwnedPopups; Wine functions should use this
2617 * to avoid interfering with application calls to ShowOwnedPopups
2618 * and to make sure the application can't prevent showing/hiding.
2620 * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2624 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2626 INT totalChild=0, count=0;
2628 WND **pWnd = WIN_BuildWinArray(WIN_GetDesktop(), 0, &totalChild);
2630 if (!pWnd) return TRUE;
2633 * Show windows Lowest first, Highest last to preserve Z-Order
2635 for (count = totalChild-1 ; count >=0; count--)
2637 if (pWnd[count]->owner && (pWnd[count]->owner->hwndSelf == owner) && (pWnd[count]->dwStyle & WS_POPUP))
2641 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2642 if (pWnd[count]->flags & WIN_NEEDS_INTERNALSOP)
2645 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2647 ShowWindow(pWnd[count]->hwndSelf,SW_SHOW);
2648 pWnd[count]->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2653 if ( IsWindowVisible(pWnd[count]->hwndSelf) && /* hide only if window is visible */
2654 !( pWnd[count]->flags & WIN_NEEDS_INTERNALSOP ) && /* don't hide if previous call already did it */
2655 !( unmanagedOnly && (pWnd[count]->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2658 * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2660 ShowWindow(pWnd[count]->hwndSelf,SW_HIDE);
2661 /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2662 pWnd[count]->flags |= WIN_NEEDS_INTERNALSOP;
2667 WIN_ReleaseDesktop();
2668 WIN_ReleaseWinArray(pWnd);
2673 /*******************************************************************
2674 * ShowOwnedPopups (USER.265)
2676 void WINAPI ShowOwnedPopups16( HWND16 owner, BOOL16 fShow )
2678 ShowOwnedPopups( owner, fShow );
2682 /*******************************************************************
2683 * ShowOwnedPopups (USER32.@)
2685 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2687 UINT totalChild=0, count=0;
2689 WND **pWnd = WIN_BuildWinArray(WIN_GetDesktop(), 0, &totalChild);
2691 if (!pWnd) return TRUE;
2693 for (; count < totalChild; count++)
2695 if (pWnd[count]->owner && (pWnd[count]->owner->hwndSelf == owner) && (pWnd[count]->dwStyle & WS_POPUP))
2699 if (pWnd[count]->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2702 * In Windows, ShowOwnedPopups(TRUE) generates WM_SHOWWINDOW messages with SW_PARENTOPENING,
2703 * regardless of the state of the owner
2705 SendMessageA(pWnd[count]->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2706 pWnd[count]->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2711 if (IsWindowVisible(pWnd[count]->hwndSelf))
2714 * In Windows, ShowOwnedPopups(FALSE) generates WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2715 * regardless of the state of the owner
2717 SendMessageA(pWnd[count]->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2718 pWnd[count]->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2724 WIN_ReleaseDesktop();
2725 WIN_ReleaseWinArray(pWnd);
2730 /*******************************************************************
2731 * GetLastActivePopup (USER.287)
2733 HWND16 WINAPI GetLastActivePopup16( HWND16 hwnd )
2735 return GetLastActivePopup( hwnd );
2738 /*******************************************************************
2739 * GetLastActivePopup (USER32.@)
2741 HWND WINAPI GetLastActivePopup( HWND hwnd )
2744 WND *wndPtr =WIN_FindWndPtr(hwnd);
2745 if (!wndPtr) return hwnd;
2746 retval = wndPtr->hwndLastActive;
2747 WIN_ReleaseWndPtr(wndPtr);
2748 if ((retval != hwnd) && (!IsWindow(retval)))
2754 /*******************************************************************
2757 * Build an array of pointers to the children of a given window.
2758 * The array must be freed with WIN_ReleaseWinArray. Return NULL
2759 * when no windows are found.
2761 WND **WIN_BuildWinArray( WND *wndPtr, UINT bwaFlags, UINT* pTotal )
2763 /* Future: this function will lock all windows associated with this array */
2765 WND **list, **ppWnd;
2767 UINT count = 0, skipOwned, skipHidden;
2770 skipHidden = bwaFlags & BWA_SKIPHIDDEN;
2771 skipOwned = bwaFlags & BWA_SKIPOWNED;
2772 skipFlags = (bwaFlags & BWA_SKIPDISABLED) ? WS_DISABLED : 0;
2773 if( bwaFlags & BWA_SKIPICONIC ) skipFlags |= WS_MINIMIZE;
2775 /* First count the windows */
2778 wndPtr = WIN_GetDesktop();
2780 pWnd = WIN_LockWndPtr(wndPtr->child);
2783 if( !(pWnd->dwStyle & skipFlags) && !(skipOwned && pWnd->owner) &&
2784 (!skipHidden || (pWnd->dwStyle & WS_VISIBLE)) )
2786 WIN_UpdateWndPtr(&pWnd,pWnd->next);
2791 /* Now build the list of all windows */
2793 if ((list = (WND **)HeapAlloc( GetProcessHeap(), 0, sizeof(WND *) * (count + 1))))
2795 for (pWnd = WIN_LockWndPtr(wndPtr->child), ppWnd = list, count = 0; pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2797 if( (pWnd->dwStyle & skipFlags) || (skipOwned && pWnd->owner) );
2798 else if( !skipHidden || pWnd->dwStyle & WS_VISIBLE )
2804 WIN_ReleaseWndPtr(pWnd);
2810 if( pTotal ) *pTotal = count;
2813 /*******************************************************************
2814 * WIN_ReleaseWinArray
2816 void WIN_ReleaseWinArray(WND **wndArray)
2818 /* Future: this function will also unlock all windows associated with wndArray */
2819 HeapFree( GetProcessHeap(), 0, wndArray );
2823 /*******************************************************************
2824 * EnumWindows (USER32.@)
2826 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2828 WND **list, **ppWnd;
2830 /* We have to build a list of all windows first, to avoid */
2831 /* unpleasant side-effects, for instance if the callback */
2832 /* function changes the Z-order of the windows. */
2834 if (!(list = WIN_BuildWinArray(WIN_GetDesktop(), 0, NULL )))
2836 WIN_ReleaseDesktop();
2840 /* Now call the callback function for every window */
2842 for (ppWnd = list; *ppWnd; ppWnd++)
2844 LRESULT lpEnumFuncRetval;
2846 /* Make sure that the window still exists */
2847 if (!IsWindow((*ppWnd)->hwndSelf)) continue;
2849 /* To avoid any deadlocks, all the locks on the windows
2850 structures must be suspended before the control
2851 is passed to the application */
2852 iWndsLocks = WIN_SuspendWndsLock();
2853 lpEnumFuncRetval = lpEnumFunc( (*ppWnd)->hwndSelf, lParam);
2854 WIN_RestoreWndsLock(iWndsLocks);
2856 if (!lpEnumFuncRetval) break;
2858 WIN_ReleaseWinArray(list);
2859 WIN_ReleaseDesktop();
2864 /**********************************************************************
2865 * WIN_EnumQueueWindows
2867 * Helper for EnumTaskWindows16 and EnumThreadWindows.
2869 static BOOL WIN_EnumQueueWindows( HQUEUE16 queue, WNDENUMPROC func, LPARAM lParam )
2871 WND **list, **ppWnd;
2873 /* This function is the same as EnumWindows(), */
2874 /* except for an added check on the window's task. */
2876 if (!(list = WIN_BuildWinArray( WIN_GetDesktop(), 0, NULL )))
2878 WIN_ReleaseDesktop();
2882 /* Now call the callback function for every window */
2884 for (ppWnd = list; *ppWnd; ppWnd++)
2888 /* Make sure that the window still exists */
2889 if (!IsWindow((*ppWnd)->hwndSelf)) continue;
2890 if ((*ppWnd)->hmemTaskQ != queue) continue;
2892 /* To avoid any deadlocks, all the locks on the windows
2893 structures must be suspended before the control
2894 is passed to the application */
2895 iWndsLocks = WIN_SuspendWndsLock();
2896 funcRetval = func( (*ppWnd)->hwndSelf, lParam );
2897 WIN_RestoreWndsLock(iWndsLocks);
2899 if (!funcRetval) break;
2901 WIN_ReleaseWinArray(list);
2902 WIN_ReleaseDesktop();
2907 /**********************************************************************
2908 * EnumTaskWindows16 (USER.225)
2910 BOOL16 WINAPI EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
2913 HQUEUE16 queue = GetTaskQueue16( hTask );
2914 if (!queue) return FALSE;
2915 return WIN_EnumQueueWindows( queue, (WNDENUMPROC)func, lParam );
2919 /**********************************************************************
2920 * EnumThreadWindows (USER32.@)
2922 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2924 HQUEUE16 queue = GetThreadQueue16( id );
2925 if (!queue) return FALSE;
2926 return WIN_EnumQueueWindows( queue, func, lParam );
2930 /**********************************************************************
2931 * WIN_EnumChildWindows
2933 * Helper function for EnumChildWindows().
2935 static BOOL16 WIN_EnumChildWindows( WND **ppWnd, WNDENUMPROC func, LPARAM lParam )
2940 for ( ; *ppWnd; ppWnd++)
2944 /* Make sure that the window still exists */
2945 if (!IsWindow((*ppWnd)->hwndSelf)) continue;
2946 /* Build children list first */
2947 childList = WIN_BuildWinArray( *ppWnd, BWA_SKIPOWNED, NULL );
2949 /* To avoid any deadlocks, all the locks on the windows
2950 structures must be suspended before the control
2951 is passed to the application */
2952 iWndsLocks = WIN_SuspendWndsLock();
2953 ret = func( (*ppWnd)->hwndSelf, lParam );
2954 WIN_RestoreWndsLock(iWndsLocks);
2958 if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2959 WIN_ReleaseWinArray(childList);
2961 if (!ret) return FALSE;
2967 /**********************************************************************
2968 * EnumChildWindows (USER32.@)
2970 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func,
2973 WND **list, *pParent;
2975 if (!(pParent = WIN_FindWndPtr( parent ))) return FALSE;
2976 if (!(list = WIN_BuildWinArray( pParent, BWA_SKIPOWNED, NULL )))
2978 WIN_ReleaseWndPtr(pParent);
2981 WIN_EnumChildWindows( list, func, lParam );
2982 WIN_ReleaseWinArray(list);
2983 WIN_ReleaseWndPtr(pParent);
2988 /*******************************************************************
2989 * AnyPopup (USER.52)
2991 BOOL16 WINAPI AnyPopup16(void)
2997 /*******************************************************************
2998 * AnyPopup (USER32.@)
3000 BOOL WINAPI AnyPopup(void)
3002 WND *wndPtr = WIN_LockWndPtr(pWndDesktop->child);
3007 if (wndPtr->owner && (wndPtr->dwStyle & WS_VISIBLE))
3012 WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
3016 WIN_ReleaseWndPtr(wndPtr);
3021 /*******************************************************************
3022 * FlashWindow (USER.105)
3024 BOOL16 WINAPI FlashWindow16( HWND16 hWnd, BOOL16 bInvert )
3026 return FlashWindow( hWnd, bInvert );
3030 /*******************************************************************
3031 * FlashWindow (USER32.@)
3033 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3035 WND *wndPtr = WIN_FindWndPtr(hWnd);
3037 TRACE("%04x\n", hWnd);
3039 if (!wndPtr) return FALSE;
3041 if (wndPtr->dwStyle & WS_MINIMIZE)
3043 if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3045 HDC hDC = GetDC(hWnd);
3047 if (!SendMessage16( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
3048 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
3050 ReleaseDC( hWnd, hDC );
3051 wndPtr->flags |= WIN_NCACTIVATED;
3055 RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3056 wndPtr->flags &= ~WIN_NCACTIVATED;
3058 WIN_ReleaseWndPtr(wndPtr);
3064 if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3065 else wparam = (hWnd == GetActiveWindow());
3067 SendMessage16( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
3068 WIN_ReleaseWndPtr(wndPtr);
3074 /*******************************************************************
3075 * SetSysModalWindow (USER.188)
3077 HWND16 WINAPI SetSysModalWindow16( HWND16 hWnd )
3079 HWND hWndOldModal = hwndSysModal;
3080 hwndSysModal = hWnd;
3081 FIXME("EMPTY STUB !! SetSysModalWindow(%04x) !\n", hWnd);
3082 return hWndOldModal;
3086 /*******************************************************************
3087 * GetSysModalWindow (USER.189)
3089 HWND16 WINAPI GetSysModalWindow16(void)
3091 return hwndSysModal;
3095 /*******************************************************************
3096 * GetWindowContextHelpId (USER32.@)
3098 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3101 WND *wnd = WIN_FindWndPtr( hwnd );
3103 retval = wnd->helpContext;
3104 WIN_ReleaseWndPtr(wnd);
3109 /*******************************************************************
3110 * SetWindowContextHelpId (USER32.@)
3112 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3114 WND *wnd = WIN_FindWndPtr( hwnd );
3115 if (!wnd) return FALSE;
3116 wnd->helpContext = id;
3117 WIN_ReleaseWndPtr(wnd);
3122 /*******************************************************************
3125 * recursively find a child that contains spDragInfo->pt point
3126 * and send WM_QUERYDROPOBJECT
3128 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
3130 BOOL16 wParam, bResult = 0;
3132 LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3133 WND *ptrQueryWnd = WIN_FindWndPtr(hQueryWnd),*ptrWnd;
3136 if( !ptrQueryWnd || !ptrDragInfo )
3139 CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3141 GetWindowRect(hQueryWnd,&tempRect);
3143 if( !PtInRect(&tempRect,pt) ||
3144 (ptrQueryWnd->dwStyle & WS_DISABLED) )
3147 if( !(ptrQueryWnd->dwStyle & WS_MINIMIZE) )
3149 tempRect = ptrQueryWnd->rectClient;
3150 if(ptrQueryWnd->parent)
3151 MapWindowPoints( ptrQueryWnd->parent->hwndSelf, 0,
3152 (LPPOINT)&tempRect, 2 );
3154 if (PtInRect( &tempRect, pt))
3158 for (ptrWnd = WIN_LockWndPtr(ptrQueryWnd->child); ptrWnd ;WIN_UpdateWndPtr(&ptrWnd,ptrWnd->next))
3160 if( ptrWnd->dwStyle & WS_VISIBLE )
3162 GetWindowRect( ptrWnd->hwndSelf, &tempRect );
3163 if (PtInRect( &tempRect, pt )) break;
3169 TRACE_(msg)("hwnd = %04x, %d %d - %d %d\n",
3170 ptrWnd->hwndSelf, ptrWnd->rectWindow.left, ptrWnd->rectWindow.top,
3171 ptrWnd->rectWindow.right, ptrWnd->rectWindow.bottom );
3172 if( !(ptrWnd->dwStyle & WS_DISABLED) )
3173 bResult = DRAG_QueryUpdate(ptrWnd->hwndSelf, spDragInfo, bNoSend);
3175 WIN_ReleaseWndPtr(ptrWnd);
3185 ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
3187 ptrDragInfo->hScope = hQueryWnd;
3189 bResult = ( bNoSend )
3190 ? ptrQueryWnd->dwExStyle & WS_EX_ACCEPTFILES
3191 : SendMessage16( hQueryWnd ,WM_QUERYDROPOBJECT ,
3192 (WPARAM16)wParam ,(LPARAM) spDragInfo );
3194 CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3197 WIN_ReleaseWndPtr(ptrQueryWnd);
3202 /*******************************************************************
3203 * DragDetect (USER.465)
3205 BOOL16 WINAPI DragDetect16( HWND16 hWnd, POINT16 pt )
3208 CONV_POINT16TO32( &pt, &pt32 );
3209 return DragDetect( hWnd, pt32 );
3212 /*******************************************************************
3213 * DragDetect (USER32.@)
3215 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3220 rect.left = pt.x - wDragWidth;
3221 rect.right = pt.x + wDragWidth;
3223 rect.top = pt.y - wDragHeight;
3224 rect.bottom = pt.y + wDragHeight;
3230 while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3232 if( msg.message == WM_LBUTTONUP )
3237 if( msg.message == WM_MOUSEMOVE )
3240 tmp.x = LOWORD(msg.lParam);
3241 tmp.y = HIWORD(msg.lParam);
3242 if( !PtInRect( &rect, tmp ))
3254 /******************************************************************************
3255 * DragObject (USER.464)
3257 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3258 HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3261 LPDRAGINFO16 lpDragInfo;
3263 HCURSOR16 hDragCursor=0, hOldCursor=0, hBummer=0;
3264 HGLOBAL16 hDragInfo = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3265 WND *wndPtr = WIN_FindWndPtr(hWnd);
3266 HCURSOR16 hCurrentCursor = 0;
3267 HWND16 hCurrentWnd = 0;
3269 lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3270 spDragInfo = K32WOWGlobalLock16(hDragInfo);
3272 if( !lpDragInfo || !spDragInfo )
3274 WIN_ReleaseWndPtr(wndPtr);
3278 hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO));
3280 if( !hBummer || !wndPtr )
3282 GlobalFree16(hDragInfo);
3283 WIN_ReleaseWndPtr(wndPtr);
3289 if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
3291 GlobalFree16(hDragInfo);
3292 WIN_ReleaseWndPtr(wndPtr);
3296 if( hDragCursor == hCursor ) hDragCursor = 0;
3297 else hCursor = hDragCursor;
3299 hOldCursor = SetCursor(hDragCursor);
3302 lpDragInfo->hWnd = hWnd;
3303 lpDragInfo->hScope = 0;
3304 lpDragInfo->wFlags = wObj;
3305 lpDragInfo->hList = szList; /* near pointer! */
3306 lpDragInfo->hOfStruct = hOfStruct;
3314 do{ WaitMessage(); }
3315 while( !PeekMessageA(&msg,0,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE) );
3317 *(lpDragInfo+1) = *lpDragInfo;
3319 lpDragInfo->pt.x = msg.pt.x;
3320 lpDragInfo->pt.y = msg.pt.y;
3322 /* update DRAGINFO struct */
3323 TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3325 if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
3326 hCurrentCursor = hCursor;
3329 hCurrentCursor = hBummer;
3330 lpDragInfo->hScope = 0;
3332 if( hCurrentCursor )
3333 SetCursor(hCurrentCursor);
3335 /* send WM_DRAGLOOP */
3336 SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3337 (LPARAM) spDragInfo );
3338 /* send WM_DRAGSELECT or WM_DRAGMOVE */
3339 if( hCurrentWnd != lpDragInfo->hScope )
3342 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3343 (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3344 HIWORD(spDragInfo)) );
3345 hCurrentWnd = lpDragInfo->hScope;
3347 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3351 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3353 } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3356 ShowCursor( FALSE );
3360 SetCursor( hOldCursor );
3361 if (hDragCursor) DestroyCursor( hDragCursor );
3364 if( hCurrentCursor != hBummer )
3365 msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3366 (WPARAM16)hWnd, (LPARAM)spDragInfo );
3369 GlobalFree16(hDragInfo);
3370 WIN_ReleaseWndPtr(wndPtr);
3372 return (DWORD)(msg.lParam);
3376 /******************************************************************************
3377 * GetWindowModuleFileNameA (USER32.@)
3379 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3381 FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3382 hwnd, lpszFileName, cchFileNameMax);
3386 /******************************************************************************
3387 * GetWindowModuleFileNameW (USER32.@)
3389 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3391 FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3392 hwnd, lpszFileName, cchFileNameMax);