Added WIN_ListParents function and renamed WIN_BuildWinArray into
[wine] / windows / win.c
1 /*
2  * Window related functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include "windef.h"
10 #include "wine/winbase16.h"
11 #include "wine/winuser16.h"
12 #include "wine/unicode.h"
13 #include "win.h"
14 #include "heap.h"
15 #include "user.h"
16 #include "dce.h"
17 #include "controls.h"
18 #include "cursoricon.h"
19 #include "hook.h"
20 #include "message.h"
21 #include "queue.h"
22 #include "task.h"
23 #include "winpos.h"
24 #include "winerror.h"
25 #include "stackframe.h"
26 #include "debugtools.h"
27
28 DEFAULT_DEBUG_CHANNEL(win);
29 DECLARE_DEBUG_CHANNEL(msg);
30
31 /**********************************************************************/
32
33 /* Desktop window */
34 static WND *pWndDesktop = NULL;
35
36 static HWND hwndSysModal = 0;
37
38 static WORD wDragWidth = 4;
39 static WORD wDragHeight= 3;
40
41 /* thread safeness */
42 extern SYSLEVEL USER_SysLevel;  /* FIXME */
43
44 /***********************************************************************
45  *           WIN_SuspendWndsLock
46  *
47  *   Suspend the lock on WND structures.
48  *   Returns the number of locks suspended
49  */
50 int WIN_SuspendWndsLock( void )
51 {
52     int isuspendedLocks = _ConfirmSysLevel( &USER_SysLevel );
53     int count = isuspendedLocks;
54
55     while ( count-- > 0 )
56         _LeaveSysLevel( &USER_SysLevel );
57
58     return isuspendedLocks;
59 }
60
61 /***********************************************************************
62  *           WIN_RestoreWndsLock
63  *
64  *  Restore the suspended locks on WND structures
65  */
66 void WIN_RestoreWndsLock( int ipreviousLocks )
67 {
68     while ( ipreviousLocks-- > 0 )
69         _EnterSysLevel( &USER_SysLevel );
70 }
71
72 /***********************************************************************
73  *           WIN_FindWndPtr
74  *
75  * Return a pointer to the WND structure corresponding to a HWND.
76  */
77 WND * WIN_FindWndPtr( HWND hwnd )
78 {
79     WND * ptr;
80     
81     if (!hwnd || HIWORD(hwnd)) goto error2;
82     ptr = (WND *) USER_HEAP_LIN_ADDR( hwnd );
83     /* Lock all WND structures for thread safeness*/
84     USER_Lock();
85     /*and increment destruction monitoring*/
86      ptr->irefCount++;
87
88     if (ptr->dwMagic != WND_MAGIC) goto error;
89     if (ptr->hwndSelf != hwnd)
90     {
91         ERR("Can't happen: hwnd %04x self pointer is %04x\n",hwnd, ptr->hwndSelf );
92         goto error;
93     }
94     /* returns a locked pointer */
95     return ptr;
96  error:
97     /* Unlock all WND structures for thread safeness*/
98     USER_Unlock();
99     /* and decrement destruction monitoring value */
100      ptr->irefCount--;
101
102 error2:
103     if ( hwnd!=0 )
104       SetLastError( ERROR_INVALID_WINDOW_HANDLE );
105     return NULL;
106 }
107
108 /***********************************************************************
109  *           WIN_LockWndPtr
110  *
111  * Use in case the wnd ptr is not initialized with WIN_FindWndPtr
112  * but by initWndPtr;
113  * Returns the locked initialisation pointer
114  */
115 WND *WIN_LockWndPtr(WND *initWndPtr)
116 {
117     if(!initWndPtr) return 0;
118
119     /* Lock all WND structures for thread safeness*/
120     USER_Lock();
121     /*and increment destruction monitoring*/
122     initWndPtr->irefCount++;
123     
124     return initWndPtr;
125
126 }
127         
128 /***********************************************************************
129  *           WIN_ReleaseWndPtr
130  *
131  * Release the pointer to the WND structure.
132  */
133 void WIN_ReleaseWndPtr(WND *wndPtr)
134 {
135     if(!wndPtr) return;
136
137     /*Decrement destruction monitoring value*/
138      wndPtr->irefCount--;
139      /* Check if it's time to release the memory*/
140      if(wndPtr->irefCount == 0 && !wndPtr->dwMagic)
141      {
142          /* Release memory */
143          USER_HEAP_FREE( wndPtr->hwndSelf);
144          wndPtr->hwndSelf = 0;
145      }
146      else if(wndPtr->irefCount < 0)
147      {
148          /* This else if is useful to monitor the WIN_ReleaseWndPtr function */
149          ERR("forgot a Lock on %p somewhere\n",wndPtr);
150      }
151      /*unlock all WND structures for thread safeness*/
152      USER_Unlock();
153 }
154
155 /***********************************************************************
156  *           WIN_UpdateWndPtr
157  *
158  * Updates the value of oldPtr to newPtr.
159  */
160 void WIN_UpdateWndPtr(WND **oldPtr, WND *newPtr)
161 {
162     WND *tmpWnd = NULL;
163     
164     tmpWnd = WIN_LockWndPtr(newPtr);
165     WIN_ReleaseWndPtr(*oldPtr);
166     *oldPtr = tmpWnd;
167
168 }
169
170
171 /***********************************************************************
172  *           WIN_UnlinkWindow
173  *
174  * Remove a window from the siblings linked list.
175  */
176 BOOL WIN_UnlinkWindow( HWND hwnd )
177 {    
178     WND *wndPtr, **ppWnd;
179     BOOL ret = FALSE;
180
181     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
182     else if(!wndPtr->parent)
183     {
184         WIN_ReleaseWndPtr(wndPtr);
185         return FALSE;
186     }
187
188     ppWnd = &wndPtr->parent->child;
189     while (*ppWnd && *ppWnd != wndPtr) ppWnd = &(*ppWnd)->next;
190     if (*ppWnd)
191     {
192         *ppWnd = wndPtr->next;
193         ret = TRUE;
194     }
195     WIN_ReleaseWndPtr(wndPtr);
196     return ret;
197 }
198
199
200 /***********************************************************************
201  *           WIN_LinkWindow
202  *
203  * Insert a window into the siblings linked list.
204  * The window is inserted after the specified window, which can also
205  * be specified as HWND_TOP or HWND_BOTTOM.
206  */
207 BOOL WIN_LinkWindow( HWND hwnd, HWND hwndInsertAfter )
208 {    
209     WND *wndPtr, **ppWnd;
210
211     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
212     else if(!wndPtr->parent)
213     {
214         WIN_ReleaseWndPtr(wndPtr);
215         return FALSE;
216     }
217     if ((hwndInsertAfter == HWND_TOP) || (hwndInsertAfter == HWND_BOTTOM))
218     {
219         ppWnd = &wndPtr->parent->child;  /* Point to first sibling hwnd */
220         if (hwndInsertAfter == HWND_BOTTOM)  /* Find last sibling hwnd */
221             while (*ppWnd) ppWnd = &(*ppWnd)->next;
222     }
223     else  /* Normal case */
224     {
225         WND * afterPtr = WIN_FindWndPtr( hwndInsertAfter );
226             if (!afterPtr)
227             {
228                 WIN_ReleaseWndPtr(wndPtr);
229                 return FALSE;
230             }
231         ppWnd = &afterPtr->next;
232         WIN_ReleaseWndPtr(afterPtr);
233     }
234     wndPtr->next = *ppWnd;
235     *ppWnd = wndPtr;
236     WIN_ReleaseWndPtr(wndPtr);
237     return TRUE;
238 }
239
240
241 /***********************************************************************
242  *           WIN_FindWinToRepaint
243  *
244  * Find a window that needs repaint.
245  */
246 HWND WIN_FindWinToRepaint( HWND hwnd )
247 {
248     HWND hwndRet;
249     WND *pWnd;
250
251     /* Note: the desktop window never gets WM_PAINT messages 
252      * The real reason why is because Windows DesktopWndProc
253      * does ValidateRgn inside WM_ERASEBKGND handler.
254      */
255     if (hwnd == GetDesktopWindow()) hwnd = 0;
256
257     pWnd = hwnd ? WIN_FindWndPtr(hwnd) : WIN_LockWndPtr(pWndDesktop->child);
258
259     for ( ; pWnd ; WIN_UpdateWndPtr(&pWnd,pWnd->next))
260     {
261         if (!(pWnd->dwStyle & WS_VISIBLE))
262         {
263             TRACE("skipping window %04x\n",
264                          pWnd->hwndSelf );
265         }
266         else if ((pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT)) &&
267                  GetWindowThreadProcessId( pWnd->hwndSelf, NULL ) == GetCurrentThreadId())
268             break;
269         
270         else if (pWnd->child )
271             if ((hwndRet = WIN_FindWinToRepaint( pWnd->child->hwndSelf )) )
272             {
273                 WIN_ReleaseWndPtr(pWnd);
274                 return hwndRet;
275     }
276     
277     }
278     
279     if(!pWnd)
280     {
281         return 0;
282     }
283     
284     hwndRet = pWnd->hwndSelf;
285
286     /* look among siblings if we got a transparent window */
287     while (pWnd && ((pWnd->dwExStyle & WS_EX_TRANSPARENT) ||
288                     !(pWnd->hrgnUpdate || (pWnd->flags & WIN_INTERNAL_PAINT))))
289     {
290         WIN_UpdateWndPtr(&pWnd,pWnd->next);
291     }
292     if (pWnd)
293     {
294         hwndRet = pWnd->hwndSelf;
295     WIN_ReleaseWndPtr(pWnd);
296     }
297     TRACE("found %04x\n",hwndRet);
298     return hwndRet;
299 }
300
301
302 /***********************************************************************
303  *           WIN_DestroyWindow
304  *
305  * Destroy storage associated to a window. "Internals" p.358
306  * returns a locked wndPtr->next
307  */
308 static WND* WIN_DestroyWindow( WND* wndPtr )
309 {
310     HWND hwnd = wndPtr->hwndSelf;
311     WND *pWnd;
312
313     TRACE("%04x\n", wndPtr->hwndSelf );
314
315     /* free child windows */
316     WIN_LockWndPtr(wndPtr->child);
317     while ((pWnd = wndPtr->child))
318     {
319         wndPtr->child = WIN_DestroyWindow( pWnd );
320         WIN_ReleaseWndPtr(pWnd);
321     }
322
323     /*
324      * Clear the update region to make sure no WM_PAINT messages will be
325      * generated for this window while processing the WM_NCDESTROY.
326      */
327     RedrawWindow( wndPtr->hwndSelf, NULL, 0,
328                   RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_NOCHILDREN);
329
330     /*
331      * Send the WM_NCDESTROY to the window being destroyed.
332      */
333     SendMessageA( wndPtr->hwndSelf, WM_NCDESTROY, 0, 0);
334
335     /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
336
337     WINPOS_CheckInternalPos( hwnd );
338     if( hwnd == GetCapture()) ReleaseCapture();
339
340     /* free resources associated with the window */
341
342     TIMER_RemoveWindowTimers( wndPtr->hwndSelf );
343     PROPERTY_RemoveWindowProps( wndPtr );
344
345     /* toss stale messages from the queue */
346
347     QUEUE_CleanupWindow( hwnd );
348     wndPtr->hmemTaskQ = 0;
349
350     if (!(wndPtr->dwStyle & WS_CHILD))
351        if (wndPtr->wIDmenu)
352        {
353            DestroyMenu( wndPtr->wIDmenu );
354            wndPtr->wIDmenu = 0;
355        }
356     if (wndPtr->hSysMenu)
357     {
358         DestroyMenu( wndPtr->hSysMenu );
359         wndPtr->hSysMenu = 0;
360     }
361     USER_Driver.pDestroyWindow( wndPtr->hwndSelf );
362     DCE_FreeWindowDCE( wndPtr->hwndSelf );    /* Always do this to catch orphaned DCs */
363     WINPROC_FreeProc( wndPtr->winproc, WIN_PROC_WINDOW );
364     CLASS_RemoveWindow( wndPtr->class );
365     wndPtr->class = NULL;
366     wndPtr->dwMagic = 0;  /* Mark it as invalid */
367
368     WIN_UpdateWndPtr(&pWnd,wndPtr->next);
369
370     return pWnd;
371 }
372
373 /***********************************************************************
374  *           WIN_DestroyThreadWindows
375  *
376  * Destroy all children of 'wnd' owned by the current thread.
377  * Return TRUE if something was done.
378  */
379 void WIN_DestroyThreadWindows( HWND hwnd )
380 {
381     HWND *list;
382     int i;
383
384     if (!(list = WIN_ListChildren( hwnd ))) return;
385     for (i = 0; list[i]; i++)
386     {
387         if (!IsWindow( list[i] )) continue;
388         if (GetWindowThreadProcessId( list[i], NULL ) == GetCurrentThreadId())
389             DestroyWindow( list[i] );
390         else
391             WIN_DestroyThreadWindows( list[i] );
392     }
393     HeapFree( GetProcessHeap(), 0, list );
394 }
395
396 /***********************************************************************
397  *           WIN_CreateDesktopWindow
398  *
399  * Create the desktop window.
400  */
401 BOOL WIN_CreateDesktopWindow(void)
402 {
403     struct tagCLASS *class;
404     HWND hwndDesktop;
405     INT wndExtra;
406     DWORD clsStyle;
407     WNDPROC winproc;
408     DCE *dce;
409     CREATESTRUCTA cs;
410
411     TRACE("Creating desktop window\n");
412
413
414     if (!WINPOS_CreateInternalPosAtom() ||
415         !(class = CLASS_AddWindow( (ATOM)LOWORD(DESKTOP_CLASS_ATOM), 0, WIN_PROC_32W,
416                                    &wndExtra, &winproc, &clsStyle, &dce )))
417         return FALSE;
418
419     hwndDesktop = USER_HEAP_ALLOC( sizeof(WND) + wndExtra );
420     if (!hwndDesktop) return FALSE;
421     pWndDesktop = (WND *) USER_HEAP_LIN_ADDR( hwndDesktop );
422
423     pWndDesktop->next              = NULL;
424     pWndDesktop->child             = NULL;
425     pWndDesktop->parent            = NULL;
426     pWndDesktop->owner             = 0;
427     pWndDesktop->class             = class;
428     pWndDesktop->dwMagic           = WND_MAGIC;
429     pWndDesktop->hwndSelf          = hwndDesktop;
430     pWndDesktop->hInstance         = 0;
431     pWndDesktop->rectWindow.left   = 0;
432     pWndDesktop->rectWindow.top    = 0;
433     pWndDesktop->rectWindow.right  = GetSystemMetrics(SM_CXSCREEN);
434     pWndDesktop->rectWindow.bottom = GetSystemMetrics(SM_CYSCREEN);
435     pWndDesktop->rectClient        = pWndDesktop->rectWindow;
436     pWndDesktop->text              = NULL;
437     pWndDesktop->hmemTaskQ         = 0;
438     pWndDesktop->hrgnUpdate        = 0;
439     pWndDesktop->hwndLastActive    = hwndDesktop;
440     pWndDesktop->dwStyle           = WS_VISIBLE | WS_CLIPCHILDREN |
441                                      WS_CLIPSIBLINGS;
442     pWndDesktop->dwExStyle         = 0;
443     pWndDesktop->clsStyle          = clsStyle;
444     pWndDesktop->dce               = NULL;
445     pWndDesktop->pVScroll          = NULL;
446     pWndDesktop->pHScroll          = NULL;
447     pWndDesktop->pProp             = NULL;
448     pWndDesktop->wIDmenu           = 0;
449     pWndDesktop->helpContext       = 0;
450     pWndDesktop->flags             = 0;
451     pWndDesktop->hSysMenu          = 0;
452     pWndDesktop->userdata          = 0;
453     pWndDesktop->winproc           = winproc;
454     pWndDesktop->cbWndExtra        = wndExtra;
455     pWndDesktop->irefCount         = 0;
456
457     cs.lpCreateParams = NULL;
458     cs.hInstance      = 0;
459     cs.hMenu          = 0;
460     cs.hwndParent     = 0;
461     cs.x              = 0;
462     cs.y              = 0;
463     cs.cx             = pWndDesktop->rectWindow.right;
464     cs.cy             = pWndDesktop->rectWindow.bottom;
465     cs.style          = pWndDesktop->dwStyle;
466     cs.dwExStyle      = pWndDesktop->dwExStyle;
467     cs.lpszName       = NULL;
468     cs.lpszClass      = DESKTOP_CLASS_ATOM;
469
470     if (!USER_Driver.pCreateWindow( hwndDesktop, &cs, FALSE )) return FALSE;
471
472     pWndDesktop->flags |= WIN_NEEDS_ERASEBKGND;
473     return TRUE;
474 }
475
476
477 /***********************************************************************
478  *           WIN_FixCoordinates
479  *
480  * Fix the coordinates - Helper for WIN_CreateWindowEx.
481  * returns default show mode in sw.
482  * Note: the feature presented as undocumented *is* in the MSDN since 1993.
483  */
484 static void WIN_FixCoordinates( CREATESTRUCTA *cs, INT *sw)
485 {
486     if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16 ||
487         cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
488     {
489         if (cs->style & (WS_CHILD | WS_POPUP))
490         {
491             if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16) cs->x = cs->y = 0;
492             if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16) cs->cx = cs->cy = 0;
493         }
494         else  /* overlapped window */
495         {
496             STARTUPINFOA info;
497
498             GetStartupInfoA( &info );
499
500             if (cs->x == CW_USEDEFAULT || cs->x == CW_USEDEFAULT16)
501             {
502                 /* Never believe Microsoft's documentation... CreateWindowEx doc says 
503                  * that if an overlapped window is created with WS_VISIBLE style bit 
504                  * set and the x parameter is set to CW_USEDEFAULT, the system ignores
505                  * the y parameter. However, disassembling NT implementation (WIN32K.SYS)
506                  * reveals that
507                  *
508                  * 1) not only it checks for CW_USEDEFAULT but also for CW_USEDEFAULT16 
509                  * 2) it does not ignore the y parameter as the docs claim; instead, it 
510                  *    uses it as second parameter to ShowWindow() unless y is either
511                  *    CW_USEDEFAULT or CW_USEDEFAULT16.
512                  * 
513                  * The fact that we didn't do 2) caused bogus windows pop up when wine
514                  * was running apps that were using this obscure feature. Example - 
515                  * calc.exe that comes with Win98 (only Win98, it's different from 
516                  * the one that comes with Win95 and NT)
517                  */
518                 if (cs->y != CW_USEDEFAULT && cs->y != CW_USEDEFAULT16) *sw = cs->y;
519                 cs->x = (info.dwFlags & STARTF_USEPOSITION) ? info.dwX : 0;
520                 cs->y = (info.dwFlags & STARTF_USEPOSITION) ? info.dwY : 0;
521             }
522
523             if (cs->cx == CW_USEDEFAULT || cs->cx == CW_USEDEFAULT16)
524             {
525                 if (info.dwFlags & STARTF_USESIZE)
526                 {
527                     cs->cx = info.dwXSize;
528                     cs->cy = info.dwYSize;
529                 }
530                 else  /* if no other hint from the app, pick 3/4 of the screen real estate */
531                 {
532                     RECT r;
533                     SystemParametersInfoA( SPI_GETWORKAREA, 0, &r, 0);
534                     cs->cx = (((r.right - r.left) * 3) / 4) - cs->x;
535                     cs->cy = (((r.bottom - r.top) * 3) / 4) - cs->y;
536                 }
537             }
538         }
539     }
540 }
541
542 /***********************************************************************
543  *           WIN_CreateWindowEx
544  *
545  * Implementation of CreateWindowEx().
546  */
547 static HWND WIN_CreateWindowEx( CREATESTRUCTA *cs, ATOM classAtom,
548                                 WINDOWPROCTYPE type )
549 {
550     INT sw = SW_SHOW; 
551     struct tagCLASS *classPtr;
552     WND *wndPtr;
553     HWND hwnd, hwndLinkAfter;
554     POINT maxSize, maxPos, minTrack, maxTrack;
555     INT wndExtra;
556     DWORD clsStyle;
557     WNDPROC winproc;
558     DCE *dce;
559     BOOL unicode = (type == WIN_PROC_32W);
560
561     TRACE("%s %s %08lx %08lx %d,%d %dx%d %04x %04x %08x %p\n",
562           (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszName) : debugres_a(cs->lpszName), 
563           (type == WIN_PROC_32W) ? debugres_w((LPWSTR)cs->lpszClass) : debugres_a(cs->lpszClass),
564           cs->dwExStyle, cs->style, cs->x, cs->y, cs->cx, cs->cy,
565           cs->hwndParent, cs->hMenu, cs->hInstance, cs->lpCreateParams );
566
567     TRACE("winproc type is %d (%s)\n", type, (type == WIN_PROC_16) ? "WIN_PROC_16" :
568             ((type == WIN_PROC_32A) ? "WIN_PROC_32A" : "WIN_PROC_32W") );
569
570     /* Find the parent window */
571
572     if (cs->hwndParent)
573     {
574         /* Make sure parent is valid */
575         if (!IsWindow( cs->hwndParent ))
576         {
577             WARN("Bad parent %04x\n", cs->hwndParent );
578             return 0;
579         }
580     } else if ((cs->style & WS_CHILD) && !(cs->style & WS_POPUP)) {
581         WARN("No parent for child window\n" );
582         return 0;  /* WS_CHILD needs a parent, but WS_POPUP doesn't */
583     }
584
585     /* Find the window class */
586     if (!(classPtr = CLASS_AddWindow( classAtom, cs->hInstance, type,
587                                       &wndExtra, &winproc, &clsStyle, &dce )))
588     {
589         WARN("Bad class '%s'\n", cs->lpszClass );
590         return 0;
591     }
592
593     WIN_FixCoordinates(cs, &sw); /* fix default coordinates */
594
595     /* Correct the window style - stage 1
596      *
597      * These are patches that appear to affect both the style loaded into the
598      * WIN structure and passed in the CreateStruct to the WM_CREATE etc.
599      *
600      * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so 
601      * why does the user get to set it?
602      */
603
604     /* This has been tested for WS_CHILD | WS_VISIBLE.  It has not been
605      * tested for WS_POPUP
606      */
607     if ((cs->dwExStyle & WS_EX_DLGMODALFRAME) ||
608         ((!(cs->dwExStyle & WS_EX_STATICEDGE)) &&
609           (cs->style & (WS_DLGFRAME | WS_THICKFRAME))))
610         cs->dwExStyle |= WS_EX_WINDOWEDGE;
611     else
612         cs->dwExStyle &= ~WS_EX_WINDOWEDGE;
613
614     /* Create the window structure */
615
616     if (!(hwnd = USER_HEAP_ALLOC( sizeof(*wndPtr) + wndExtra - sizeof(wndPtr->wExtra) )))
617     {
618         TRACE("out of memory\n" );
619         return 0;
620     }
621
622     /* Fill the window structure */
623
624     wndPtr = WIN_LockWndPtr((WND *) USER_HEAP_LIN_ADDR( hwnd ));
625     wndPtr->next  = NULL;
626     wndPtr->child = NULL;
627
628     if ((cs->style & WS_CHILD) && cs->hwndParent)
629     {
630         wndPtr->parent = WIN_FindWndPtr( cs->hwndParent );
631         wndPtr->owner  = 0;
632         WIN_ReleaseWndPtr(wndPtr->parent);
633     }
634     else
635     {
636         wndPtr->parent = pWndDesktop;
637         if (!cs->hwndParent || (cs->hwndParent == pWndDesktop->hwndSelf))
638             wndPtr->owner = 0;
639         else
640             wndPtr->owner = GetAncestor( cs->hwndParent, GA_ROOT );
641     }
642     
643
644     wndPtr->class          = classPtr;
645     wndPtr->winproc        = winproc;
646     wndPtr->dwMagic        = WND_MAGIC;
647     wndPtr->hwndSelf       = hwnd;
648     wndPtr->hInstance      = cs->hInstance;
649     wndPtr->text           = NULL;
650     wndPtr->hmemTaskQ      = InitThreadInput16( 0, 0 );
651     wndPtr->hrgnUpdate     = 0;
652     wndPtr->hrgnWnd        = 0;
653     wndPtr->hwndLastActive = hwnd;
654     wndPtr->dwStyle        = cs->style & ~WS_VISIBLE;
655     wndPtr->dwExStyle      = cs->dwExStyle;
656     wndPtr->clsStyle       = clsStyle;
657     wndPtr->wIDmenu        = 0;
658     wndPtr->helpContext    = 0;
659     wndPtr->flags          = (type == WIN_PROC_16) ? 0 : WIN_ISWIN32;
660     wndPtr->pVScroll       = NULL;
661     wndPtr->pHScroll       = NULL;
662     wndPtr->pProp          = NULL;
663     wndPtr->userdata       = 0;
664     wndPtr->hSysMenu       = (wndPtr->dwStyle & WS_SYSMENU)
665                              ? MENU_GetSysMenu( hwnd, 0 ) : 0;
666     wndPtr->cbWndExtra     = wndExtra;
667     wndPtr->irefCount      = 1;
668
669     if (wndExtra) memset( wndPtr->wExtra, 0, wndExtra);
670
671     /* Call the WH_CBT hook */
672
673     hwndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
674  ? HWND_BOTTOM : HWND_TOP;
675
676     if (HOOK_IsHooked( WH_CBT ))
677     {
678         CBT_CREATEWNDA cbtc;
679         LRESULT ret;
680
681         cbtc.lpcs = cs;
682         cbtc.hwndInsertAfter = hwndLinkAfter;
683         ret = (type == WIN_PROC_32W) ? HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND, hwnd, (LPARAM)&cbtc)
684                       : HOOK_CallHooksA(WH_CBT, HCBT_CREATEWND, hwnd, (LPARAM)&cbtc);
685         if (ret)
686         {
687             TRACE("CBT-hook returned 0\n");
688             USER_HEAP_FREE( hwnd );
689             CLASS_RemoveWindow( classPtr );
690             hwnd =  0;
691             goto end;
692         }
693     }
694
695     /* Correct the window style - stage 2 */
696
697     if (!(cs->style & WS_CHILD))
698     {
699         wndPtr->dwStyle |= WS_CLIPSIBLINGS;
700         if (!(cs->style & WS_POPUP))
701         {
702             wndPtr->dwStyle |= WS_CAPTION;
703             wndPtr->flags |= WIN_NEED_SIZE;
704         }
705     }
706
707     /* Get class or window DC if needed */
708
709     if (clsStyle & CS_OWNDC) wndPtr->dce = DCE_AllocDCE(hwnd,DCE_WINDOW_DC);
710     else if (clsStyle & CS_CLASSDC) wndPtr->dce = dce;
711     else wndPtr->dce = NULL;
712
713     /* Initialize the dimensions before sending WM_GETMINMAXINFO */
714
715     wndPtr->rectWindow.left   = cs->x;
716     wndPtr->rectWindow.top    = cs->y;
717     wndPtr->rectWindow.right  = cs->x + cs->cx;
718     wndPtr->rectWindow.bottom = cs->y + cs->cy;
719     wndPtr->rectClient        = wndPtr->rectWindow;
720
721     /* Send the WM_GETMINMAXINFO message and fix the size if needed */
722
723     if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
724     {
725         WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
726         if (maxSize.x < cs->cx) cs->cx = maxSize.x;
727         if (maxSize.y < cs->cy) cs->cy = maxSize.y;
728         if (cs->cx < minTrack.x ) cs->cx = minTrack.x;
729         if (cs->cy < minTrack.y ) cs->cy = minTrack.y;
730     }
731
732     if (cs->cx < 0) cs->cx = 0;
733     if (cs->cy < 0) cs->cy = 0;
734
735     wndPtr->rectWindow.left   = cs->x;
736     wndPtr->rectWindow.top    = cs->y;
737     wndPtr->rectWindow.right  = cs->x + cs->cx;
738     wndPtr->rectWindow.bottom = cs->y + cs->cy;
739     wndPtr->rectClient        = wndPtr->rectWindow;
740
741     /* Set the window menu */
742
743     if ((wndPtr->dwStyle & (WS_CAPTION | WS_CHILD)) == WS_CAPTION )
744     {
745         if (cs->hMenu) SetMenu(hwnd, cs->hMenu);
746         else
747         {
748             LPCSTR menuName = (LPCSTR)GetClassLongA( hwnd, GCL_MENUNAME );
749             if (menuName)
750             {
751                 if (HIWORD(cs->hInstance))
752                     cs->hMenu = LoadMenuA(cs->hInstance,menuName);
753                 else
754                     cs->hMenu = LoadMenu16(cs->hInstance,menuName);
755
756                 if (cs->hMenu) SetMenu( hwnd, cs->hMenu );
757             }
758         }
759     }
760     else wndPtr->wIDmenu = (UINT)cs->hMenu;
761
762     if (!USER_Driver.pCreateWindow( wndPtr->hwndSelf, cs, unicode))
763     {
764         WARN("aborted by WM_xxCREATE!\n");
765         WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr ));
766         CLASS_RemoveWindow( classPtr );
767         WIN_ReleaseWndPtr(wndPtr);
768         return 0;
769     }
770
771     if( (wndPtr->dwStyle & WS_CHILD) && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
772     {
773         /* Notify the parent window only */
774
775         SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
776                       MAKEWPARAM(WM_CREATE, wndPtr->wIDmenu), (LPARAM)hwnd );
777         if( !IsWindow(hwnd) )
778         {
779             hwnd = 0;
780             goto end;
781         }
782     }
783
784     if (cs->style & WS_VISIBLE)
785     {
786         /* in case WS_VISIBLE got set in the meantime */
787         wndPtr->dwStyle &= ~WS_VISIBLE;
788         ShowWindow( hwnd, sw );
789     }
790
791     /* Call WH_SHELL hook */
792
793     if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
794         HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWCREATED, hwnd, 0 );
795
796     TRACE("created window %04x\n", hwnd);
797  end:
798     WIN_ReleaseWndPtr(wndPtr);
799     return hwnd;
800 }
801
802
803 /***********************************************************************
804  *              CreateWindow (USER.41)
805  */
806 HWND16 WINAPI CreateWindow16( LPCSTR className, LPCSTR windowName,
807                               DWORD style, INT16 x, INT16 y, INT16 width,
808                               INT16 height, HWND16 parent, HMENU16 menu,
809                               HINSTANCE16 instance, LPVOID data ) 
810 {
811     return CreateWindowEx16( 0, className, windowName, style,
812                            x, y, width, height, parent, menu, instance, data );
813 }
814
815
816 /***********************************************************************
817  *              CreateWindowEx (USER.452)
818  */
819 HWND16 WINAPI CreateWindowEx16( DWORD exStyle, LPCSTR className,
820                                 LPCSTR windowName, DWORD style, INT16 x,
821                                 INT16 y, INT16 width, INT16 height,
822                                 HWND16 parent, HMENU16 menu,
823                                 HINSTANCE16 instance, LPVOID data ) 
824 {
825     ATOM classAtom;
826     CREATESTRUCTA cs;
827     char buffer[256];
828
829     /* Find the class atom */
830
831     if (HIWORD(className))
832     {
833         if (!(classAtom = GlobalFindAtomA( className )))
834         {
835             ERR( "bad class name %s\n", debugres_a(className) );
836             return 0;
837         }
838     }
839     else
840     {
841         classAtom = LOWORD(className);
842         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
843         {
844             ERR( "bad atom %x\n", classAtom);
845             return 0;
846         }
847         className = buffer;
848     }
849
850     /* Fix the coordinates */
851
852     cs.x  = (x == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)x;
853     cs.y  = (y == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)y;
854     cs.cx = (width == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)width;
855     cs.cy = (height == CW_USEDEFAULT16) ? CW_USEDEFAULT : (INT)height;
856
857     /* Create the window */
858
859     cs.lpCreateParams = data;
860     cs.hInstance      = (HINSTANCE)instance;
861     cs.hMenu          = (HMENU)menu;
862     cs.hwndParent     = (HWND)parent;
863     cs.style          = style;
864     cs.lpszName       = windowName;
865     cs.lpszClass      = className;
866     cs.dwExStyle      = exStyle;
867
868     return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_16 );
869 }
870
871
872 /***********************************************************************
873  *              CreateWindowExA (USER32.@)
874  */
875 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
876                                  LPCSTR windowName, DWORD style, INT x,
877                                  INT y, INT width, INT height,
878                                  HWND parent, HMENU menu,
879                                  HINSTANCE instance, LPVOID data )
880 {
881     ATOM classAtom;
882     CREATESTRUCTA cs;
883     char buffer[256];
884
885     if(!instance)
886         instance=GetModuleHandleA(NULL);
887
888     if(exStyle & WS_EX_MDICHILD)
889         return CreateMDIWindowA(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
890
891     /* Find the class atom */
892
893     if (HIWORD(className))
894     {
895         if (!(classAtom = GlobalFindAtomA( className )))
896         {
897             ERR( "bad class name %s\n", debugres_a(className) );
898             return 0;
899         }
900     }
901     else
902     {
903         classAtom = LOWORD(className);
904         if (!GlobalGetAtomNameA( classAtom, buffer, sizeof(buffer) ))
905         {
906             ERR( "bad atom %x\n", classAtom);
907             return 0;
908         }
909         className = buffer;
910     }
911
912     /* Create the window */
913
914     cs.lpCreateParams = data;
915     cs.hInstance      = instance;
916     cs.hMenu          = menu;
917     cs.hwndParent     = parent;
918     cs.x              = x;
919     cs.y              = y;
920     cs.cx             = width;
921     cs.cy             = height;
922     cs.style          = style;
923     cs.lpszName       = windowName;
924     cs.lpszClass      = className;
925     cs.dwExStyle      = exStyle;
926
927     return WIN_CreateWindowEx( &cs, classAtom, WIN_PROC_32A );
928 }
929
930
931 /***********************************************************************
932  *              CreateWindowExW (USER32.@)
933  */
934 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
935                                  LPCWSTR windowName, DWORD style, INT x,
936                                  INT y, INT width, INT height,
937                                  HWND parent, HMENU menu,
938                                  HINSTANCE instance, LPVOID data )
939 {
940     ATOM classAtom;
941     CREATESTRUCTW cs;
942     WCHAR buffer[256];
943
944     if(!instance)
945         instance=GetModuleHandleA(NULL);
946
947     if(exStyle & WS_EX_MDICHILD)
948         return CreateMDIWindowW(className, windowName, style, x, y, width, height, parent, instance, (LPARAM)data);
949
950     /* Find the class atom */
951
952     if (HIWORD(className))
953     {
954         if (!(classAtom = GlobalFindAtomW( className )))
955         {
956             ERR( "bad class name %s\n", debugres_w(className) );
957             return 0;
958         }
959     }
960     else
961     {
962         classAtom = LOWORD(className);
963         if (!GlobalGetAtomNameW( classAtom, buffer, sizeof(buffer)/sizeof(WCHAR) ))
964         {
965             ERR( "bad atom %x\n", classAtom);
966             return 0;
967         }
968         className = buffer;
969     }
970
971     /* Create the window */
972
973     cs.lpCreateParams = data;
974     cs.hInstance      = instance;
975     cs.hMenu          = menu;
976     cs.hwndParent     = parent;
977     cs.x              = x;
978     cs.y              = y;
979     cs.cx             = width;
980     cs.cy             = height;
981     cs.style          = style;
982     cs.lpszName       = windowName;
983     cs.lpszClass      = className;
984     cs.dwExStyle      = exStyle;
985
986     /* Note: we rely on the fact that CREATESTRUCTA and */
987     /* CREATESTRUCTW have the same layout. */
988     return WIN_CreateWindowEx( (CREATESTRUCTA *)&cs, classAtom, WIN_PROC_32W );
989 }
990
991
992 /***********************************************************************
993  *           WIN_SendDestroyMsg
994  */
995 static void WIN_SendDestroyMsg( HWND hwnd )
996 {
997     if( CARET_GetHwnd() == hwnd) DestroyCaret();
998     if (USER_Driver.pResetSelectionOwner)
999         USER_Driver.pResetSelectionOwner( hwnd, TRUE );
1000
1001     /*
1002      * Send the WM_DESTROY to the window.
1003      */
1004     SendMessageA( hwnd, WM_DESTROY, 0, 0);
1005
1006     /*
1007      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1008      * make sure that the window still exists when we come back.
1009      */
1010     if (IsWindow(hwnd))
1011     {
1012         HWND* pWndArray;
1013         int i;
1014
1015         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1016
1017         /* start from the end (FIXME: is this needed?) */
1018         for (i = 0; pWndArray[i]; i++) ;
1019
1020         while (--i >= 0)
1021         {
1022             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1023         }
1024         HeapFree( GetProcessHeap(), 0, pWndArray );
1025     }
1026     else
1027       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1028 }
1029
1030
1031 /***********************************************************************
1032  *              DestroyWindow (USER.53)
1033  */
1034 BOOL16 WINAPI DestroyWindow16( HWND16 hwnd )
1035 {
1036     return DestroyWindow(hwnd);
1037 }
1038
1039
1040 /***********************************************************************
1041  *              DestroyWindow (USER32.@)
1042  */
1043 BOOL WINAPI DestroyWindow( HWND hwnd )
1044 {
1045     WND * wndPtr;
1046     BOOL retvalue;
1047     HWND h;
1048
1049     TRACE("(%04x)\n", hwnd);
1050
1051     /* Initialization */
1052
1053     if (hwnd == GetDesktopWindow()) return FALSE;   /* Can't destroy desktop */
1054
1055     /* Look whether the focus is within the tree of windows we will
1056      * be destroying.
1057      */
1058     h = GetFocus();
1059     if (h == hwnd || IsChild( hwnd, h ))
1060     {
1061         HWND parent = GetAncestor( hwnd, GA_PARENT );
1062         if (parent == GetDesktopWindow()) parent = 0;
1063         SetFocus( parent );
1064     }
1065
1066       /* Call hooks */
1067
1068     if( HOOK_CallHooksA( WH_CBT, HCBT_DESTROYWND, hwnd, 0L) ) return FALSE;
1069
1070     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1071     if (!(wndPtr->dwStyle & WS_CHILD) && !wndPtr->owner)
1072     {
1073         HOOK_CallHooksA( WH_SHELL, HSHELL_WINDOWDESTROYED, hwnd, 0L );
1074         /* FIXME: clean up palette - see "Internals" p.352 */
1075     }
1076
1077     if( !QUEUE_IsExitingQueue(wndPtr->hmemTaskQ) )
1078         if( wndPtr->dwStyle & WS_CHILD && !(wndPtr->dwExStyle & WS_EX_NOPARENTNOTIFY) )
1079         {
1080             /* Notify the parent window only */
1081             SendMessageA( wndPtr->parent->hwndSelf, WM_PARENTNOTIFY,
1082                             MAKEWPARAM(WM_DESTROY, wndPtr->wIDmenu), (LPARAM)hwnd );
1083             if( !IsWindow(hwnd) )
1084             {
1085                 retvalue = TRUE;
1086                 goto end;
1087             }
1088         }
1089
1090     if (USER_Driver.pResetSelectionOwner)
1091         USER_Driver.pResetSelectionOwner( hwnd, FALSE ); /* before the window is unmapped */
1092
1093       /* Hide the window */
1094
1095     if (wndPtr->dwStyle & WS_VISIBLE)
1096     {
1097         ShowWindow( hwnd, SW_HIDE );
1098         if (!IsWindow(hwnd))
1099         {
1100             retvalue = TRUE;
1101             goto end;
1102         }
1103     }
1104
1105       /* Recursively destroy owned windows */
1106
1107     if( !(wndPtr->dwStyle & WS_CHILD) )
1108     {
1109       for (;;)
1110       {
1111           int i, got_one = 0;
1112           HWND *list = WIN_ListChildren( wndPtr->parent->hwndSelf );
1113           if (list)
1114           {
1115               for (i = 0; list[i]; i++)
1116               {
1117                   WND *siblingPtr = WIN_FindWndPtr( list[i] );
1118                   if (!siblingPtr) continue;
1119                   if (siblingPtr->owner == hwnd)
1120                   {
1121                       if (siblingPtr->hmemTaskQ == wndPtr->hmemTaskQ)
1122                       {
1123                           WIN_ReleaseWndPtr( siblingPtr );
1124                           DestroyWindow( list[i] );
1125                           got_one = 1;
1126                           continue;
1127                       }
1128                       else siblingPtr->owner = 0;
1129                   }
1130                   WIN_ReleaseWndPtr( siblingPtr );
1131               }
1132               HeapFree( GetProcessHeap(), 0, list );
1133           }
1134           if (!got_one) break;
1135       }
1136
1137       WINPOS_ActivateOtherWindow(wndPtr->hwndSelf);
1138
1139       if (wndPtr->owner)
1140       {
1141           WND *owner = WIN_FindWndPtr( wndPtr->owner );
1142           if (owner->hwndLastActive == hwnd) owner->hwndLastActive = wndPtr->owner;
1143           WIN_ReleaseWndPtr( owner );
1144       }
1145     }
1146
1147       /* Send destroy messages */
1148
1149     WIN_SendDestroyMsg( hwnd );
1150     if (!IsWindow(hwnd))
1151     {
1152         retvalue = TRUE;
1153         goto end;
1154     }
1155
1156       /* Unlink now so we won't bother with the children later on */
1157
1158     if( wndPtr->parent ) WIN_UnlinkWindow(hwnd);
1159
1160       /* Destroy the window storage */
1161
1162     WIN_ReleaseWndPtr(WIN_DestroyWindow( wndPtr ));
1163     retvalue = TRUE;
1164 end:
1165     WIN_ReleaseWndPtr(wndPtr);
1166     return retvalue;
1167 }
1168
1169
1170 /***********************************************************************
1171  *              CloseWindow (USER.43)
1172  */
1173 BOOL16 WINAPI CloseWindow16( HWND16 hwnd )
1174 {
1175     return CloseWindow( hwnd );
1176 }
1177
1178  
1179 /***********************************************************************
1180  *              CloseWindow (USER32.@)
1181  */
1182 BOOL WINAPI CloseWindow( HWND hwnd )
1183 {
1184     WND * wndPtr = WIN_FindWndPtr( hwnd );
1185     BOOL retvalue;
1186     
1187     if (!wndPtr || (wndPtr->dwStyle & WS_CHILD))
1188     {
1189         retvalue = FALSE;
1190         goto end;
1191     }
1192     ShowWindow( hwnd, SW_MINIMIZE );
1193     retvalue = TRUE;
1194 end:
1195     WIN_ReleaseWndPtr(wndPtr);
1196     return retvalue;
1197
1198 }
1199
1200  
1201 /***********************************************************************
1202  *              OpenIcon (USER.44)
1203  */
1204 BOOL16 WINAPI OpenIcon16( HWND16 hwnd )
1205 {
1206     return OpenIcon( hwnd );
1207 }
1208
1209
1210 /***********************************************************************
1211  *              OpenIcon (USER32.@)
1212  */
1213 BOOL WINAPI OpenIcon( HWND hwnd )
1214 {
1215     if (!IsIconic( hwnd )) return FALSE;
1216     ShowWindow( hwnd, SW_SHOWNORMAL );
1217     return TRUE;
1218 }
1219
1220
1221 /***********************************************************************
1222  *           WIN_FindWindow
1223  *
1224  * Implementation of FindWindow() and FindWindowEx().
1225  */
1226 static HWND WIN_FindWindow( HWND parent, HWND child, ATOM className, LPCWSTR title )
1227 {
1228     HWND *list;
1229     HWND retvalue;
1230     int i = 0, len = 0;
1231     WCHAR *buffer = NULL;
1232
1233     if (!parent) parent = GetDesktopWindow();
1234     if (title)
1235     {
1236         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1237         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1238     }
1239
1240     if (!(list = WIN_ListChildren( parent )))
1241     {
1242         if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1243         return 0;
1244     }
1245
1246     if (child)
1247     {
1248         while (list[i] && list[i] != child) i++;
1249         if (!list[i]) return 0;
1250         i++;  /* start from next window */
1251     }
1252
1253     for ( ; list[i]; i++)
1254     {
1255         if (className && (GetClassWord(list[i], GCW_ATOM) != className))
1256             continue;  /* Not the right class */
1257
1258         /* Now check the title */
1259         if (!title) break;
1260         if (GetWindowTextW( list[i], buffer, len ) && !strcmpiW( buffer, title )) break;
1261     }
1262     retvalue = list[i];
1263     HeapFree( GetProcessHeap(), 0, list );
1264     if (buffer) HeapFree( GetProcessHeap(), 0, buffer );
1265
1266     /* In this case we need to check whether other processes
1267        own a window with the given paramters on the Desktop,
1268        but we don't, so let's at least warn about it */
1269     if (!retvalue) FIXME("Returning 0 without checking other processes\n");
1270     return retvalue;
1271 }
1272
1273
1274
1275 /***********************************************************************
1276  *              FindWindow (USER.50)
1277  */
1278 HWND16 WINAPI FindWindow16( LPCSTR className, LPCSTR title )
1279 {
1280     return FindWindowA( className, title );
1281 }
1282
1283
1284 /***********************************************************************
1285  *              FindWindowEx (USER.427)
1286  */
1287 HWND16 WINAPI FindWindowEx16( HWND16 parent, HWND16 child, LPCSTR className, LPCSTR title )
1288 {
1289     return FindWindowExA( parent, child, className, title );
1290 }
1291
1292
1293 /***********************************************************************
1294  *              FindWindowA (USER32.@)
1295  */
1296 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1297 {
1298     HWND ret = FindWindowExA( 0, 0, className, title );
1299     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1300     return ret;
1301 }
1302
1303
1304 /***********************************************************************
1305  *              FindWindowExA (USER32.@)
1306  */
1307 HWND WINAPI FindWindowExA( HWND parent, HWND child,
1308                                LPCSTR className, LPCSTR title )
1309 {
1310     ATOM atom = 0;
1311     LPWSTR buffer;
1312     HWND hwnd;
1313
1314     if (className)
1315     {
1316         /* If the atom doesn't exist, then no class */
1317         /* with this name exists either. */
1318         if (!(atom = GlobalFindAtomA( className ))) 
1319         {
1320             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1321             return 0;
1322         }
1323     }
1324
1325     buffer = HEAP_strdupAtoW( GetProcessHeap(), 0, title );
1326     hwnd = WIN_FindWindow( parent, child, atom, buffer );
1327     HeapFree( GetProcessHeap(), 0, buffer );
1328     return hwnd;
1329 }
1330
1331
1332 /***********************************************************************
1333  *              FindWindowExW (USER32.@)
1334  */
1335 HWND WINAPI FindWindowExW( HWND parent, HWND child,
1336                                LPCWSTR className, LPCWSTR title )
1337 {
1338     ATOM atom = 0;
1339
1340     if (className)
1341     {
1342         /* If the atom doesn't exist, then no class */
1343         /* with this name exists either. */
1344         if (!(atom = GlobalFindAtomW( className )))
1345         {
1346             SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1347             return 0;
1348         }
1349     }
1350     return WIN_FindWindow( parent, child, atom, title );
1351 }
1352
1353
1354 /***********************************************************************
1355  *              FindWindowW (USER32.@)
1356  */
1357 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1358 {
1359     return FindWindowExW( 0, 0, className, title );
1360 }
1361
1362
1363 /**********************************************************************
1364  *              GetDesktopWindow (USER.286)
1365  */
1366 HWND16 WINAPI GetDesktopWindow16(void)
1367 {
1368     return (HWND16)pWndDesktop->hwndSelf;
1369 }
1370
1371
1372 /**********************************************************************
1373  *              GetDesktopWindow (USER32.@)
1374  */
1375 HWND WINAPI GetDesktopWindow(void)
1376 {
1377     if (pWndDesktop) return pWndDesktop->hwndSelf;
1378     ERR( "You need the -desktop option when running with native USER\n" );
1379     ExitProcess(1);
1380     return 0;
1381 }
1382
1383
1384 /**********************************************************************
1385  *              GetDesktopHwnd (USER.278)
1386  *
1387  * Exactly the same thing as GetDesktopWindow(), but not documented.
1388  * Don't ask me why...
1389  */
1390 HWND16 WINAPI GetDesktopHwnd16(void)
1391 {
1392     return (HWND16)pWndDesktop->hwndSelf;
1393 }
1394
1395
1396 /*******************************************************************
1397  *              EnableWindow (USER.34)
1398  */
1399 BOOL16 WINAPI EnableWindow16( HWND16 hwnd, BOOL16 enable )
1400 {
1401     return EnableWindow( hwnd, enable );
1402 }
1403
1404
1405 /*******************************************************************
1406  *              EnableWindow (USER32.@)
1407  */
1408 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1409 {
1410     WND *wndPtr;
1411     BOOL retvalue;
1412
1413     TRACE("( %x, %d )\n", hwnd, enable);
1414
1415     if (USER_Driver.pEnableWindow)
1416         return USER_Driver.pEnableWindow( hwnd, enable );
1417
1418     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1419
1420     retvalue = ((wndPtr->dwStyle & WS_DISABLED) != 0);
1421
1422     if (enable && (wndPtr->dwStyle & WS_DISABLED))
1423     {
1424         wndPtr->dwStyle &= ~WS_DISABLED; /* Enable window */
1425         SendMessageA( hwnd, WM_ENABLE, TRUE, 0 );
1426     }
1427     else if (!enable && !(wndPtr->dwStyle & WS_DISABLED))
1428     {
1429         SendMessageA( wndPtr->hwndSelf, WM_CANCELMODE, 0, 0);
1430
1431         wndPtr->dwStyle |= WS_DISABLED; /* Disable window */
1432
1433         if (hwnd == GetFocus())
1434             SetFocus( 0 );  /* A disabled window can't have the focus */
1435
1436         if (hwnd == GetCapture())
1437             ReleaseCapture();  /* A disabled window can't capture the mouse */
1438
1439         SendMessageA( hwnd, WM_ENABLE, FALSE, 0 );
1440     }
1441     WIN_ReleaseWndPtr(wndPtr);
1442     return retvalue;
1443 }
1444
1445
1446 /***********************************************************************
1447  *              IsWindowEnabled (USER.35)
1448  */ 
1449 BOOL16 WINAPI IsWindowEnabled16(HWND16 hWnd)
1450 {
1451     return IsWindowEnabled(hWnd);
1452 }
1453
1454
1455 /***********************************************************************
1456  *              IsWindowEnabled (USER32.@)
1457  */ 
1458 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1459 {
1460     WND * wndPtr; 
1461     BOOL retvalue;
1462
1463     if (!(wndPtr = WIN_FindWndPtr(hWnd))) return FALSE;
1464     retvalue = !(wndPtr->dwStyle & WS_DISABLED);
1465     WIN_ReleaseWndPtr(wndPtr);
1466     return retvalue;
1467
1468 }
1469
1470
1471 /***********************************************************************
1472  *              IsWindowUnicode (USER32.@)
1473  */
1474 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1475 {
1476     WND * wndPtr; 
1477     BOOL retvalue;
1478
1479     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
1480     retvalue = (WINPROC_GetProcType( wndPtr->winproc ) == WIN_PROC_32W);
1481     WIN_ReleaseWndPtr(wndPtr);
1482     return retvalue;
1483 }
1484
1485
1486 /**********************************************************************
1487  *              GetWindowWord (USER.133)
1488  */
1489 WORD WINAPI GetWindowWord16( HWND16 hwnd, INT16 offset )
1490 {
1491     return GetWindowWord( hwnd, offset );
1492 }
1493
1494
1495 /**********************************************************************
1496  *              GetWindowWord (USER32.@)
1497  */
1498 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
1499 {
1500     WORD retvalue;
1501     WND * wndPtr = WIN_FindWndPtr( hwnd );
1502     if (!wndPtr) return 0;
1503     if (offset >= 0)
1504     {
1505         if (offset + sizeof(WORD) > wndPtr->cbWndExtra)
1506         {
1507             WARN("Invalid offset %d\n", offset );
1508             retvalue = 0;
1509             goto end;
1510         }
1511         retvalue = *(WORD *)(((char *)wndPtr->wExtra) + offset);
1512         goto end;
1513     }
1514     switch(offset)
1515     {
1516     case GWW_ID:         
1517         if (HIWORD(wndPtr->wIDmenu))
1518                 WARN("GWW_ID: discards high bits of 0x%08x!\n",
1519                     wndPtr->wIDmenu);
1520         retvalue = (WORD)wndPtr->wIDmenu;
1521         goto end;
1522     case GWW_HWNDPARENT: 
1523         retvalue =  GetParent(hwnd);
1524         goto end;
1525     case GWW_HINSTANCE:  
1526         if (HIWORD(wndPtr->hInstance))
1527                 WARN("GWW_HINSTANCE: discards high bits of 0x%08x!\n",
1528                     wndPtr->hInstance);
1529         retvalue = (WORD)wndPtr->hInstance;
1530         goto end;
1531     default:
1532         WARN("Invalid offset %d\n", offset );
1533         retvalue = 0;
1534         goto end;
1535     }
1536 end:
1537     WIN_ReleaseWndPtr(wndPtr);
1538     return retvalue;
1539 }
1540
1541 /**********************************************************************
1542  *              SetWindowWord (USER.134)
1543  */
1544 WORD WINAPI SetWindowWord16( HWND16 hwnd, INT16 offset, WORD newval )
1545 {
1546     return SetWindowWord( hwnd, offset, newval );
1547 }
1548
1549
1550 /**********************************************************************
1551  *              SetWindowWord (USER32.@)
1552  */
1553 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
1554 {
1555     WORD *ptr, retval;
1556     WND * wndPtr = WIN_FindWndPtr( hwnd );
1557     if (!wndPtr) return 0;
1558     if (offset >= 0)
1559     {
1560         if (offset + sizeof(WORD) > wndPtr->cbWndExtra)
1561         {
1562             WARN("Invalid offset %d\n", offset );
1563             retval = 0;
1564             goto end;
1565         }
1566         ptr = (WORD *)(((char *)wndPtr->wExtra) + offset);
1567     }
1568     else switch(offset)
1569     {
1570         case GWW_ID:        ptr = (WORD *)&wndPtr->wIDmenu; break;
1571         case GWW_HINSTANCE: ptr = (WORD *)&wndPtr->hInstance; break;
1572         case GWW_HWNDPARENT: retval = SetParent( hwnd, newval );
1573                              goto end;
1574         default:
1575             WARN("Invalid offset %d\n", offset );
1576             retval = 0;
1577             goto end;
1578     }
1579     retval = *ptr;
1580     *ptr = newval;
1581 end:
1582     WIN_ReleaseWndPtr(wndPtr);
1583     return retval;
1584 }
1585
1586
1587 /**********************************************************************
1588  *           WIN_GetWindowLong
1589  *
1590  * Helper function for GetWindowLong().
1591  */
1592 static LONG WIN_GetWindowLong( HWND hwnd, INT offset, WINDOWPROCTYPE type )
1593 {
1594     LONG retvalue;
1595     WND * wndPtr = WIN_FindWndPtr( hwnd );
1596     if (!wndPtr) return 0;
1597     if (offset >= 0)
1598     {
1599         if (offset + sizeof(LONG) > wndPtr->cbWndExtra)
1600         {
1601             WARN("Invalid offset %d\n", offset );
1602             retvalue = 0;
1603             goto end;
1604         }
1605         retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1606         /* Special case for dialog window procedure */
1607         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1608         {
1609             retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1610             goto end;
1611     }
1612         goto end;
1613     }
1614     switch(offset)
1615     {
1616         case GWL_USERDATA:   retvalue = wndPtr->userdata;
1617                              goto end;
1618         case GWL_STYLE:      retvalue = wndPtr->dwStyle;
1619                              goto end;
1620         case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle;
1621                              goto end;
1622         case GWL_ID:         retvalue = (LONG)wndPtr->wIDmenu;
1623                              goto end;
1624         case GWL_WNDPROC:    retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc,
1625                                                            type );
1626                              goto end;
1627         case GWL_HWNDPARENT: retvalue = GetParent(hwnd);
1628                              goto end;
1629         case GWL_HINSTANCE:  retvalue = wndPtr->hInstance;
1630                              goto end;
1631         default:
1632             WARN("Unknown offset %d\n", offset );
1633     }
1634     retvalue = 0;
1635 end:
1636     WIN_ReleaseWndPtr(wndPtr);
1637     return retvalue;
1638 }
1639
1640
1641 /**********************************************************************
1642  *           WIN_SetWindowLong
1643  *
1644  * Helper function for SetWindowLong().
1645  *
1646  * 0 is the failure code. However, in the case of failure SetLastError
1647  * must be set to distinguish between a 0 return value and a failure.
1648  *
1649  * FIXME: The error values for SetLastError may not be right. Can
1650  *        someone check with the real thing?
1651  */
1652 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1653                                WINDOWPROCTYPE type )
1654 {
1655     LONG *ptr, retval;
1656     WND * wndPtr = WIN_FindWndPtr( hwnd );
1657     STYLESTRUCT style;
1658     
1659     TRACE("%x=%p %x %lx %x\n",hwnd, wndPtr, offset, newval, type);
1660
1661     if (!wndPtr)
1662     {
1663        /* Is this the right error? */
1664        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1665        return 0;
1666     }
1667
1668     if (offset >= 0)
1669     {
1670         if (offset + sizeof(LONG) > wndPtr->cbWndExtra)
1671         {
1672             WARN("Invalid offset %d\n", offset );
1673
1674             /* Is this the right error? */
1675             SetLastError( ERROR_OUTOFMEMORY );
1676
1677             retval = 0;
1678             goto end;
1679         }
1680         ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1681         /* Special case for dialog window procedure */
1682         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1683         {
1684             retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1685             WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval, 
1686                              type, WIN_PROC_WINDOW );
1687             goto end;
1688         }
1689     }
1690     else switch(offset)
1691     {
1692         case GWL_ID:
1693                 ptr = (DWORD*)&wndPtr->wIDmenu;
1694                 break;
1695         case GWL_HINSTANCE:
1696                 retval = SetWindowWord( hwnd, offset, newval );
1697                 goto end;
1698         case GWL_WNDPROC:
1699                 retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
1700                 WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval, 
1701                                                 type, WIN_PROC_WINDOW );
1702                 goto end;
1703         case GWL_STYLE:
1704                 style.styleOld = wndPtr->dwStyle;
1705                 style.styleNew = newval;
1706                 SendMessageA(hwnd,WM_STYLECHANGING,GWL_STYLE,(LPARAM)&style);
1707                 wndPtr->dwStyle = style.styleNew;
1708                 SendMessageA(hwnd,WM_STYLECHANGED,GWL_STYLE,(LPARAM)&style);
1709                 retval = style.styleOld;
1710                 goto end;
1711                     
1712         case GWL_USERDATA: 
1713                 ptr = &wndPtr->userdata; 
1714                 break;
1715         case GWL_EXSTYLE:  
1716                 style.styleOld = wndPtr->dwExStyle;
1717                 style.styleNew = newval;
1718                 SendMessageA(hwnd,WM_STYLECHANGING,GWL_EXSTYLE,(LPARAM)&style);
1719                 wndPtr->dwExStyle = newval;
1720                 SendMessageA(hwnd,WM_STYLECHANGED,GWL_EXSTYLE,(LPARAM)&style);
1721                 retval = style.styleOld;
1722                 goto end;
1723
1724         default:
1725             WARN("Invalid offset %d\n", offset );
1726
1727             /* Don't think this is right error but it should do */
1728             SetLastError( ERROR_OUTOFMEMORY );
1729
1730             retval = 0;
1731             goto end;
1732     }
1733     retval = *ptr;
1734     *ptr = newval;
1735 end:
1736     WIN_ReleaseWndPtr(wndPtr);
1737     return retval;
1738 }
1739
1740
1741 /**********************************************************************
1742  *              GetWindowLong (USER.135)
1743  */
1744 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
1745 {
1746     return WIN_GetWindowLong( (HWND)hwnd, offset, WIN_PROC_16 );
1747 }
1748
1749
1750 /**********************************************************************
1751  *              GetWindowLongA (USER32.@)
1752  */
1753 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
1754 {
1755     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
1756 }
1757
1758
1759 /**********************************************************************
1760  *              GetWindowLongW (USER32.@)
1761  */
1762 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
1763 {
1764     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
1765 }
1766
1767
1768 /**********************************************************************
1769  *              SetWindowLong (USER.136)
1770  */
1771 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
1772 {
1773     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_16 );
1774 }
1775
1776
1777 /**********************************************************************
1778  *              SetWindowLongA (USER32.@)
1779  */
1780 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
1781 {
1782     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
1783 }
1784
1785
1786 /**********************************************************************
1787  *              SetWindowLongW (USER32.@) Set window attribute
1788  *
1789  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
1790  * value in a window's extra memory. 
1791  *
1792  * The _hwnd_ parameter specifies the window.  is the handle to a
1793  * window that has extra memory. The _newval_ parameter contains the
1794  * new attribute or extra memory value.  If positive, the _offset_
1795  * parameter is the byte-addressed location in the window's extra
1796  * memory to set.  If negative, _offset_ specifies the window
1797  * attribute to set, and should be one of the following values:
1798  *
1799  * GWL_EXSTYLE      The window's extended window style
1800  *
1801  * GWL_STYLE        The window's window style. 
1802  *
1803  * GWL_WNDPROC      Pointer to the window's window procedure. 
1804  *
1805  * GWL_HINSTANCE    The window's pplication instance handle.
1806  *
1807  * GWL_ID           The window's identifier.
1808  *
1809  * GWL_USERDATA     The window's user-specified data. 
1810  *
1811  * If the window is a dialog box, the _offset_ parameter can be one of 
1812  * the following values:
1813  *
1814  * DWL_DLGPROC      The address of the window's dialog box procedure.
1815  *
1816  * DWL_MSGRESULT    The return value of a message 
1817  *                  that the dialog box procedure processed.
1818  *
1819  * DWL_USER         Application specific information.
1820  *
1821  * RETURNS
1822  *
1823  * If successful, returns the previous value located at _offset_. Otherwise,
1824  * returns 0.
1825  *
1826  * NOTES
1827  *
1828  * Extra memory for a window class is specified by a nonzero cbWndExtra 
1829  * parameter of the WNDCLASS structure passed to RegisterClass() at the
1830  * time of class creation.
1831  *  
1832  * Using GWL_WNDPROC to set a new window procedure effectively creates
1833  * a window subclass. Use CallWindowProc() in the new windows procedure
1834  * to pass messages to the superclass's window procedure.
1835  *
1836  * The user data is reserved for use by the application which created
1837  * the window.
1838  *
1839  * Do not use GWL_STYLE to change the window's WS_DISABLE style;
1840  * instead, call the EnableWindow() function to change the window's
1841  * disabled state.
1842  *
1843  * Do not use GWL_HWNDPARENT to reset the window's parent, use
1844  * SetParent() instead.
1845  *
1846  * Win95:
1847  * When offset is GWL_STYLE and the calling app's ver is 4.0,
1848  * it sends WM_STYLECHANGING before changing the settings
1849  * and WM_STYLECHANGED afterwards.
1850  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
1851  *
1852  * BUGS
1853  *
1854  * GWL_STYLE does not dispatch WM_STYLE... messages.
1855  *
1856  * CONFORMANCE
1857  *
1858  * ECMA-234, Win32 
1859  *
1860  */
1861 LONG WINAPI SetWindowLongW( 
1862     HWND hwnd,  /* [in] window to alter */
1863     INT offset, /* [in] offset, in bytes, of location to alter */
1864     LONG newval /* [in] new value of location */
1865 ) {
1866     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
1867 }
1868
1869
1870 /*******************************************************************
1871  *              GetWindowText (USER.36)
1872  */
1873 INT16 WINAPI GetWindowText16( HWND16 hwnd, SEGPTR lpString, INT16 nMaxCount )
1874 {
1875     return (INT16)SendMessage16(hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString);
1876 }
1877
1878
1879 /*******************************************************************
1880  *              GetWindowTextA (USER32.@)
1881  */
1882 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
1883 {
1884     return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount,
1885                                   (LPARAM)lpString );
1886 }
1887
1888 /*******************************************************************
1889  *              InternalGetWindowText (USER32.@)
1890  */
1891 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
1892 {
1893     WND *win = WIN_FindWndPtr( hwnd );
1894     if (!win) return 0;
1895     if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
1896     else lpString[0] = 0;
1897     WIN_ReleaseWndPtr( win );
1898     return strlenW(lpString);
1899 }
1900
1901
1902 /*******************************************************************
1903  *              GetWindowTextW (USER32.@)
1904  */
1905 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
1906 {
1907     return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount,
1908                                   (LPARAM)lpString );
1909 }
1910
1911
1912 /*******************************************************************
1913  *              SetWindowText (USER.37)
1914  */
1915 BOOL16 WINAPI SetWindowText16( HWND16 hwnd, SEGPTR lpString )
1916 {
1917     return (BOOL16)SendMessage16( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1918 }
1919
1920
1921 /*******************************************************************
1922  *              SetWindowText  (USER32.@)
1923  *              SetWindowTextA (USER32.@)
1924  */
1925 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
1926 {
1927     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1928 }
1929
1930
1931 /*******************************************************************
1932  *              SetWindowTextW (USER32.@)
1933  */
1934 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
1935 {
1936     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
1937 }
1938
1939
1940 /*******************************************************************
1941  *              GetWindowTextLength (USER.38)
1942  */
1943 INT16 WINAPI GetWindowTextLength16( HWND16 hwnd )
1944 {
1945     return (INT16)GetWindowTextLengthA( hwnd );
1946 }
1947
1948
1949 /*******************************************************************
1950  *              GetWindowTextLengthA (USER32.@)
1951  */
1952 INT WINAPI GetWindowTextLengthA( HWND hwnd )
1953 {
1954     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1955 }
1956
1957 /*******************************************************************
1958  *              GetWindowTextLengthW (USER32.@)
1959  */
1960 INT WINAPI GetWindowTextLengthW( HWND hwnd )
1961 {
1962     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
1963 }
1964
1965
1966 /*******************************************************************
1967  *              IsWindow (USER.47)
1968  */
1969 BOOL16 WINAPI IsWindow16( HWND16 hwnd )
1970 {
1971     CURRENT_STACK16->es = USER_HeapSel;
1972     return IsWindow( hwnd );
1973 }
1974
1975
1976 /*******************************************************************
1977  *              IsWindow (USER32.@)
1978  */
1979 BOOL WINAPI IsWindow( HWND hwnd )
1980 {
1981     WND * wndPtr;
1982     BOOL retvalue;
1983     
1984     if(!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
1985     retvalue = (wndPtr->dwMagic == WND_MAGIC);
1986     WIN_ReleaseWndPtr(wndPtr);
1987     return retvalue;
1988     
1989 }
1990
1991
1992 /*****************************************************************
1993  *              GetParent (USER.46)
1994  */
1995 HWND16 WINAPI GetParent16( HWND16 hwnd )
1996 {
1997     return (HWND16)GetParent( hwnd );
1998 }
1999
2000
2001 /*****************************************************************
2002  *              GetParent (USER32.@)
2003  */
2004 HWND WINAPI GetParent( HWND hwnd )
2005 {
2006     WND *wndPtr;
2007     HWND retvalue = 0;
2008
2009     if ((wndPtr = WIN_FindWndPtr(hwnd)))
2010     {
2011         if (wndPtr->dwStyle & WS_CHILD)
2012             retvalue = wndPtr->parent->hwndSelf;
2013         else if (wndPtr->dwStyle & WS_POPUP)
2014             retvalue = wndPtr->owner;
2015         WIN_ReleaseWndPtr(wndPtr);
2016     }
2017     return retvalue;
2018 }
2019
2020
2021 /*****************************************************************
2022  *              GetAncestor (USER32.@)
2023  */
2024 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2025 {
2026     HWND ret;
2027     WND *wndPtr, *parent;
2028
2029     if (hwnd == GetDesktopWindow()) return 0;
2030     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2031     parent = wndPtr->parent;
2032
2033     switch(type)
2034     {
2035     case GA_PARENT:
2036         WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2037         break;
2038     case GA_ROOT:
2039         while (wndPtr->parent->hwndSelf != GetDesktopWindow())
2040             WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2041         break;
2042     case GA_ROOTOWNER:
2043         while (wndPtr->parent->hwndSelf != GetDesktopWindow())
2044             WIN_UpdateWndPtr( &wndPtr, wndPtr->parent );
2045         while (wndPtr->owner)
2046         {
2047             WND *ptr = WIN_FindWndPtr( wndPtr->owner );
2048             WIN_ReleaseWndPtr( wndPtr );
2049             wndPtr = ptr;
2050         }
2051         break;
2052     }
2053     ret = wndPtr->hwndSelf;
2054     WIN_ReleaseWndPtr( wndPtr );
2055     return ret;
2056 }
2057
2058
2059 /*****************************************************************
2060  *              SetParent (USER.233)
2061  */
2062 HWND16 WINAPI SetParent16( HWND16 hwndChild, HWND16 hwndNewParent )
2063 {
2064     return SetParent( hwndChild, hwndNewParent );
2065 }
2066
2067
2068 /*****************************************************************
2069  *              SetParent (USER32.@)
2070  */
2071 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2072 {
2073     WND *wndPtr;
2074     WND *pWndParent;
2075     DWORD dwStyle;
2076     HWND retvalue;
2077
2078     if (hwnd == GetDesktopWindow()) /* sanity check */
2079     {
2080         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2081         return 0;
2082     }
2083
2084     if (USER_Driver.pSetParent)
2085         return USER_Driver.pSetParent( hwnd, parent );
2086
2087     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return 0;
2088
2089     dwStyle = wndPtr->dwStyle;
2090
2091     if (!parent) parent = GetDesktopWindow();
2092
2093     if (!(pWndParent = WIN_FindWndPtr(parent)))
2094     {
2095         WIN_ReleaseWndPtr( wndPtr );
2096         return 0;
2097     }
2098
2099     /* Windows hides the window first, then shows it again
2100      * including the WM_SHOWWINDOW messages and all */
2101     if (dwStyle & WS_VISIBLE) ShowWindow( hwnd, SW_HIDE );
2102
2103     retvalue = wndPtr->parent->hwndSelf;  /* old parent */
2104     if (pWndParent != wndPtr->parent)
2105     {
2106         WIN_UnlinkWindow(wndPtr->hwndSelf);
2107         wndPtr->parent = pWndParent;
2108
2109         if (parent != GetDesktopWindow()) /* a child window */
2110         {
2111             if( !( wndPtr->dwStyle & WS_CHILD ) )
2112             {
2113                 if( wndPtr->wIDmenu != 0)
2114                 {
2115                     DestroyMenu( (HMENU) wndPtr->wIDmenu );
2116                     wndPtr->wIDmenu = 0;
2117                 }
2118             }
2119         }
2120         WIN_LinkWindow(wndPtr->hwndSelf, HWND_TOP);
2121     }
2122     WIN_ReleaseWndPtr( pWndParent );
2123     WIN_ReleaseWndPtr( wndPtr );
2124
2125     /* SetParent additionally needs to make hwnd the topmost window
2126        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2127        WM_WINDOWPOSCHANGED notification messages. 
2128     */
2129     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2130                   SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOSIZE|
2131                   ((dwStyle & WS_VISIBLE)?SWP_SHOWWINDOW:0));
2132     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2133      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2134     return retvalue;
2135 }
2136
2137
2138 /*******************************************************************
2139  *              IsChild (USER.48)
2140  */
2141 BOOL16 WINAPI IsChild16( HWND16 parent, HWND16 child )
2142 {
2143     return IsChild(parent,child);
2144 }
2145
2146
2147 /*******************************************************************
2148  *              IsChild (USER32.@)
2149  */
2150 BOOL WINAPI IsChild( HWND parent, HWND child )
2151 {
2152     HWND *list = WIN_ListParents( child );
2153     int i;
2154     BOOL ret;
2155
2156     if (!list) return FALSE;
2157     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2158     ret = (list[i] != 0);
2159     HeapFree( GetProcessHeap(), 0, list );
2160     return ret;
2161 }
2162
2163
2164 /***********************************************************************
2165  *              IsWindowVisible (USER.49)
2166  */
2167 BOOL16 WINAPI IsWindowVisible16( HWND16 hwnd )
2168 {
2169     return IsWindowVisible(hwnd);
2170 }
2171
2172
2173 /***********************************************************************
2174  *              IsWindowVisible (USER32.@)
2175  */
2176 BOOL WINAPI IsWindowVisible( HWND hwnd )
2177 {
2178     HWND *list;
2179     BOOL retval;
2180     int i;
2181
2182     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2183     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2184     for (i = 0; list[i]; i++)
2185         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2186     retval = !list[i];
2187     HeapFree( GetProcessHeap(), 0, list );
2188     return retval;
2189 }
2190
2191
2192 /***********************************************************************
2193  *           WIN_IsWindowDrawable
2194  *
2195  * hwnd is drawable when it is visible, all parents are not
2196  * minimized, and it is itself not minimized unless we are
2197  * trying to draw its default class icon.
2198  */
2199 BOOL WIN_IsWindowDrawable( WND* wnd, BOOL icon )
2200 {
2201     HWND *list;
2202     BOOL retval;
2203     int i;
2204
2205     if (!(wnd->dwStyle & WS_VISIBLE)) return FALSE;
2206     if ((wnd->dwStyle & WS_MINIMIZE) &&
2207         icon && GetClassLongA( wnd->hwndSelf, GCL_HICON ))  return FALSE;
2208
2209     if (!(list = WIN_ListParents( wnd->hwndSelf ))) return TRUE;
2210     for (i = 0; list[i]; i++)
2211         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2212             break;
2213     retval = !list[i];
2214     HeapFree( GetProcessHeap(), 0, list );
2215     return retval;
2216 }
2217
2218
2219 /*******************************************************************
2220  *              GetTopWindow (USER.229)
2221  */
2222 HWND16 WINAPI GetTopWindow16( HWND16 hwnd )
2223 {
2224     return GetTopWindow(hwnd);
2225 }
2226
2227
2228 /*******************************************************************
2229  *              GetTopWindow (USER32.@)
2230  */
2231 HWND WINAPI GetTopWindow( HWND hwnd )
2232 {
2233     if (!hwnd) hwnd = GetDesktopWindow();
2234     return GetWindow( hwnd, GW_CHILD );
2235 }
2236
2237
2238 /*******************************************************************
2239  *              GetWindow (USER.262)
2240  */
2241 HWND16 WINAPI GetWindow16( HWND16 hwnd, WORD rel )
2242 {
2243     return GetWindow( hwnd,rel );
2244 }
2245
2246
2247 /*******************************************************************
2248  *              GetWindow (USER32.@)
2249  */
2250 HWND WINAPI GetWindow( HWND hwnd, WORD rel )
2251 {
2252     HWND retval;
2253     
2254     WND * wndPtr = WIN_FindWndPtr( hwnd );
2255     if (!wndPtr) return 0;
2256     switch(rel)
2257     {
2258     case GW_HWNDFIRST:
2259         retval = wndPtr->parent ? wndPtr->parent->child->hwndSelf : 0;
2260         goto end;
2261         
2262     case GW_HWNDLAST:
2263         if (!wndPtr->parent)
2264         {
2265             retval = 0;  /* Desktop window */
2266             goto end;
2267         }
2268         while (wndPtr->next)
2269         {
2270             WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
2271         }
2272         retval = wndPtr->hwndSelf;
2273         goto end;
2274         
2275     case GW_HWNDNEXT:
2276         retval = wndPtr->next ? wndPtr->next->hwndSelf : 0;
2277         goto end;
2278         
2279     case GW_HWNDPREV:
2280         if (!wndPtr->parent)
2281         {
2282             retval = 0;  /* Desktop window */
2283             goto end;
2284         }
2285         WIN_UpdateWndPtr(&wndPtr,wndPtr->parent->child); /* First sibling */
2286         if (wndPtr->hwndSelf == hwnd)
2287         {
2288             retval = 0;  /* First in list */
2289             goto end;
2290         }
2291         while (wndPtr->next)
2292         {
2293             if (wndPtr->next->hwndSelf == hwnd)
2294             {
2295                 retval = wndPtr->hwndSelf;
2296                 goto end;
2297             }
2298             WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
2299         }
2300         retval = 0;
2301         goto end;
2302         
2303     case GW_OWNER:
2304         retval = wndPtr->owner;
2305         goto end;
2306
2307     case GW_CHILD:
2308         retval = wndPtr->child ? wndPtr->child->hwndSelf : 0;
2309         goto end;
2310     }
2311     retval = 0;
2312 end:
2313     WIN_ReleaseWndPtr(wndPtr);
2314     return retval;
2315 }
2316
2317
2318 /*******************************************************************
2319  *              GetNextWindow (USER.230)
2320  */
2321 HWND16 WINAPI GetNextWindow16( HWND16 hwnd, WORD flag )
2322 {
2323     if ((flag != GW_HWNDNEXT) && (flag != GW_HWNDPREV)) return 0;
2324     return GetWindow16( hwnd, flag );
2325 }
2326
2327 /***********************************************************************
2328  *           WIN_InternalShowOwnedPopups 
2329  *
2330  * Internal version of ShowOwnedPopups; Wine functions should use this
2331  * to avoid interfering with application calls to ShowOwnedPopups
2332  * and to make sure the application can't prevent showing/hiding.
2333  *
2334  * Set unmanagedOnly to TRUE to show/hide unmanaged windows only. 
2335  *
2336  */
2337
2338 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2339 {
2340     int count = 0;
2341     WND *pWnd;
2342     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2343
2344     if (!win_array) return TRUE;
2345
2346     /*
2347      * Show windows Lowest first, Highest last to preserve Z-Order
2348      */
2349     while (win_array[count]) count++;
2350     while (--count >= 0)
2351     {
2352         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2353         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2354
2355         if (pWnd->dwStyle & WS_POPUP)
2356         {
2357             if (fShow)
2358             {
2359                 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2360                 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2361                 {
2362                     /*
2363                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2364                      */
2365                     ShowWindow(pWnd->hwndSelf,SW_SHOW);
2366                     pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2367                 }
2368             }
2369             else
2370             {
2371                 if ( IsWindowVisible(pWnd->hwndSelf) &&                   /* hide only if window is visible */
2372                      !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) &&          /* don't hide if previous call already did it */
2373                      !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2374                 {
2375                     /*
2376                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2377                      */
2378                     ShowWindow(pWnd->hwndSelf,SW_HIDE);
2379                     /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2380                     pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2381                 }
2382             }
2383         }
2384         WIN_ReleaseWndPtr( pWnd );
2385     }
2386     HeapFree( GetProcessHeap(), 0, win_array );
2387
2388     return TRUE;
2389 }
2390
2391 /*******************************************************************
2392  *              ShowOwnedPopups (USER.265)
2393  */
2394 void WINAPI ShowOwnedPopups16( HWND16 owner, BOOL16 fShow )
2395 {
2396     ShowOwnedPopups( owner, fShow );
2397 }
2398
2399
2400 /*******************************************************************
2401  *              ShowOwnedPopups (USER32.@)
2402  */
2403 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2404 {
2405     int count = 0;
2406     WND *pWnd;
2407     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2408
2409     if (!win_array) return TRUE;
2410
2411     while (win_array[count]) count++;
2412     while (--count >= 0)
2413     {
2414         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2415         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2416
2417         if (pWnd->dwStyle & WS_POPUP)
2418         {
2419             if (fShow)
2420             {
2421                 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2422                 {
2423                     /* In Windows, ShowOwnedPopups(TRUE) generates
2424                      * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2425                      * regardless of the state of the owner
2426                      */
2427                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2428                     pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2429                 }
2430             }
2431             else
2432             {
2433                 if (IsWindowVisible(pWnd->hwndSelf))
2434                 {
2435                     /* In Windows, ShowOwnedPopups(FALSE) generates
2436                      * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2437                      * regardless of the state of the owner
2438                      */
2439                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2440                     pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2441                 }
2442             }
2443         }
2444         WIN_ReleaseWndPtr( pWnd );
2445     }
2446     HeapFree( GetProcessHeap(), 0, win_array );
2447     return TRUE;
2448 }
2449
2450
2451 /*******************************************************************
2452  *              GetLastActivePopup (USER.287)
2453  */
2454 HWND16 WINAPI GetLastActivePopup16( HWND16 hwnd )
2455 {
2456     return GetLastActivePopup( hwnd );
2457 }
2458
2459 /*******************************************************************
2460  *              GetLastActivePopup (USER32.@)
2461  */
2462 HWND WINAPI GetLastActivePopup( HWND hwnd )
2463 {
2464     HWND retval;
2465     WND *wndPtr =WIN_FindWndPtr(hwnd);
2466     if (!wndPtr) return hwnd;
2467     retval = wndPtr->hwndLastActive;
2468     WIN_ReleaseWndPtr(wndPtr);
2469     if ((retval != hwnd) && (!IsWindow(retval)))
2470        retval = hwnd;
2471     return retval;
2472 }
2473
2474
2475 /*******************************************************************
2476  *           WIN_ListParents
2477  *
2478  * Build an array of all parents of a given window, starting with
2479  * the immediate parent. The array must be freed with HeapFree.
2480  * Returns NULL if window is a top-level window.
2481  */
2482 HWND *WIN_ListParents( HWND hwnd )
2483 {
2484     WND *parent, *wndPtr = WIN_FindWndPtr( hwnd );
2485     HWND *list = NULL;
2486     UINT i, count = 0;
2487
2488     /* First count the windows */
2489
2490     if (!wndPtr) return NULL;
2491
2492     parent = wndPtr->parent;
2493     while (parent && parent->hwndSelf != GetDesktopWindow())
2494     {
2495         count++;
2496         parent = parent->parent;
2497     }
2498
2499     if (count)
2500     {
2501         if ((list = HeapAlloc( GetProcessHeap(), 0, sizeof(HWND) * (count + 1) )))
2502         {
2503             parent = wndPtr->parent;
2504             for (i = 0; i < count; i++)
2505             {
2506                 list[i] = parent->hwndSelf;
2507                 parent = parent->parent;
2508             }
2509             list[i] = 0;
2510         }
2511     }
2512
2513     WIN_ReleaseWndPtr( wndPtr );
2514     return list;
2515 }
2516
2517
2518 /*******************************************************************
2519  *           WIN_ListChildren
2520  *
2521  * Build an array of the children of a given window. The array must be
2522  * freed with HeapFree. Returns NULL when no windows are found.
2523  */
2524 HWND *WIN_ListChildren( HWND hwnd )
2525 {
2526     WND *pWnd, *wndPtr = WIN_FindWndPtr( hwnd );
2527     HWND *list, *phwnd;
2528     UINT count = 0;
2529
2530     /* First count the windows */
2531
2532     if (!wndPtr) return NULL;
2533
2534     pWnd = WIN_LockWndPtr(wndPtr->child);
2535     while (pWnd)
2536     {
2537         count++;
2538         WIN_UpdateWndPtr(&pWnd,pWnd->next);
2539     }
2540
2541     if( count )
2542     {
2543         /* Now build the list of all windows */
2544
2545         if ((list = HeapAlloc( GetProcessHeap(), 0, sizeof(HWND) * (count + 1))))
2546         {
2547             for (pWnd = WIN_LockWndPtr(wndPtr->child), phwnd = list, count = 0; pWnd; WIN_UpdateWndPtr(&pWnd,pWnd->next))
2548             {
2549                 *phwnd++ = pWnd->hwndSelf;
2550                 count++;
2551             }
2552             WIN_ReleaseWndPtr(pWnd);
2553             *phwnd = 0;
2554         }
2555         else count = 0;
2556     } else list = NULL;
2557
2558     WIN_ReleaseWndPtr( wndPtr );
2559     return list;
2560 }
2561
2562
2563 /*******************************************************************
2564  *              EnumWindows (USER32.@)
2565  */
2566 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2567 {
2568     HWND *list;
2569     BOOL ret = TRUE;
2570     int i, iWndsLocks;
2571
2572     /* We have to build a list of all windows first, to avoid */
2573     /* unpleasant side-effects, for instance if the callback */
2574     /* function changes the Z-order of the windows.          */
2575
2576     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE;
2577
2578     /* Now call the callback function for every window */
2579
2580     iWndsLocks = WIN_SuspendWndsLock();
2581     for (i = 0; list[i]; i++)
2582     {
2583         /* Make sure that the window still exists */
2584         if (!IsWindow( list[i] )) continue;
2585         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2586     }
2587     WIN_RestoreWndsLock(iWndsLocks);
2588     HeapFree( GetProcessHeap(), 0, list );
2589     return ret;
2590 }
2591
2592
2593 /**********************************************************************
2594  *              EnumTaskWindows16   (USER.225)
2595  */
2596 BOOL16 WINAPI EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
2597                                  LPARAM lParam )
2598 {
2599     TDB *tdb = TASK_GetPtr( hTask );
2600     if (!tdb) return FALSE;
2601     return EnumThreadWindows( (DWORD)tdb->teb->tid, (WNDENUMPROC)func, lParam );
2602 }
2603
2604
2605 /**********************************************************************
2606  *              EnumThreadWindows (USER32.@)
2607  */
2608 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2609 {
2610     HWND *list;
2611     int i, iWndsLocks;
2612
2613     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE;
2614
2615     /* Now call the callback function for every window */
2616
2617     iWndsLocks = WIN_SuspendWndsLock();
2618     for (i = 0; list[i]; i++)
2619     {
2620         if (GetWindowThreadProcessId( list[i], NULL ) != id) continue;
2621         if (!func( list[i], lParam )) break;
2622     }
2623     WIN_RestoreWndsLock(iWndsLocks);
2624     HeapFree( GetProcessHeap(), 0, list );
2625     return TRUE;
2626 }
2627
2628
2629 /**********************************************************************
2630  *           WIN_EnumChildWindows
2631  *
2632  * Helper function for EnumChildWindows().
2633  */
2634 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2635 {
2636     HWND *childList;
2637     BOOL ret = FALSE;
2638
2639     for ( ; *list; list++)
2640     {
2641         /* Make sure that the window still exists */
2642         if (!IsWindow( *list )) continue;
2643         /* skip owned windows */
2644         if (GetWindow( *list, GW_OWNER )) continue;
2645         /* Build children list first */
2646         childList = WIN_ListChildren( *list );
2647
2648         ret = func( *list, lParam );
2649
2650         if (childList)
2651         {
2652             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2653             HeapFree( GetProcessHeap(), 0, childList );
2654         }
2655         if (!ret) return FALSE;
2656     }
2657     return TRUE;
2658 }
2659
2660
2661 /**********************************************************************
2662  *              EnumChildWindows (USER32.@)
2663  */
2664 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2665 {
2666     HWND *list;
2667     int iWndsLocks;
2668
2669     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2670     iWndsLocks = WIN_SuspendWndsLock();
2671     WIN_EnumChildWindows( list, func, lParam );
2672     WIN_RestoreWndsLock(iWndsLocks);
2673     HeapFree( GetProcessHeap(), 0, list );
2674     return TRUE;
2675 }
2676
2677
2678 /*******************************************************************
2679  *              AnyPopup (USER.52)
2680  */
2681 BOOL16 WINAPI AnyPopup16(void)
2682 {
2683     return AnyPopup();
2684 }
2685
2686
2687 /*******************************************************************
2688  *              AnyPopup (USER32.@)
2689  */
2690 BOOL WINAPI AnyPopup(void)
2691 {
2692     int i;
2693     BOOL retvalue;
2694     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2695
2696     if (!list) return FALSE;
2697     for (i = 0; list[i]; i++)
2698     {
2699         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2700     }
2701     retvalue = (list[i] != 0);
2702     HeapFree( GetProcessHeap(), 0, list );
2703     return retvalue;
2704 }
2705
2706
2707 /*******************************************************************
2708  *              FlashWindow (USER.105)
2709  */
2710 BOOL16 WINAPI FlashWindow16( HWND16 hWnd, BOOL16 bInvert )
2711 {
2712     return FlashWindow( hWnd, bInvert );
2713 }
2714
2715
2716 /*******************************************************************
2717  *              FlashWindow (USER32.@)
2718  */
2719 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2720 {
2721     WND *wndPtr = WIN_FindWndPtr(hWnd);
2722
2723     TRACE("%04x\n", hWnd);
2724
2725     if (!wndPtr) return FALSE;
2726
2727     if (wndPtr->dwStyle & WS_MINIMIZE)
2728     {
2729         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2730         {
2731             HDC hDC = GetDC(hWnd);
2732             
2733             if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
2734                 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
2735             
2736             ReleaseDC( hWnd, hDC );
2737             wndPtr->flags |= WIN_NCACTIVATED;
2738         }
2739         else
2740         {
2741             RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2742             wndPtr->flags &= ~WIN_NCACTIVATED;
2743         }
2744         WIN_ReleaseWndPtr(wndPtr);
2745         return TRUE;
2746     }
2747     else
2748     {
2749         WPARAM16 wparam;
2750         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2751         else wparam = (hWnd == GetActiveWindow());
2752
2753         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2754         WIN_ReleaseWndPtr(wndPtr);
2755         return wparam;
2756     }
2757 }
2758
2759
2760 /*******************************************************************
2761  *              SetSysModalWindow (USER.188)
2762  */
2763 HWND16 WINAPI SetSysModalWindow16( HWND16 hWnd )
2764 {
2765     HWND hWndOldModal = hwndSysModal;
2766     hwndSysModal = hWnd;
2767     FIXME("EMPTY STUB !! SetSysModalWindow(%04x) !\n", hWnd);
2768     return hWndOldModal;
2769 }
2770
2771
2772 /*******************************************************************
2773  *              GetSysModalWindow (USER.189)
2774  */
2775 HWND16 WINAPI GetSysModalWindow16(void)
2776 {
2777     return hwndSysModal;
2778 }
2779
2780
2781 /*******************************************************************
2782  *              GetWindowContextHelpId (USER32.@)
2783  */
2784 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
2785 {
2786     DWORD retval;
2787     WND *wnd = WIN_FindWndPtr( hwnd );
2788     if (!wnd) return 0;
2789     retval = wnd->helpContext;
2790     WIN_ReleaseWndPtr(wnd);
2791     return retval;
2792 }
2793
2794
2795 /*******************************************************************
2796  *              SetWindowContextHelpId (USER32.@)
2797  */
2798 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
2799 {
2800     WND *wnd = WIN_FindWndPtr( hwnd );
2801     if (!wnd) return FALSE;
2802     wnd->helpContext = id;
2803     WIN_ReleaseWndPtr(wnd);
2804     return TRUE;
2805 }
2806
2807
2808 /*******************************************************************
2809  *                      DRAG_QueryUpdate
2810  *
2811  * recursively find a child that contains spDragInfo->pt point 
2812  * and send WM_QUERYDROPOBJECT
2813  */
2814 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
2815 {
2816     BOOL16 wParam, bResult = 0;
2817     POINT pt;
2818     LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
2819     RECT tempRect;
2820
2821     if (!ptrDragInfo) return FALSE;
2822
2823     CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
2824
2825     GetWindowRect(hQueryWnd,&tempRect);
2826
2827     if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
2828
2829     if (!IsIconic( hQueryWnd ))
2830     {
2831         WND *ptrWnd, *ptrQueryWnd = WIN_FindWndPtr(hQueryWnd);
2832
2833         tempRect = ptrQueryWnd->rectClient;
2834         if(ptrQueryWnd->parent)
2835             MapWindowPoints( ptrQueryWnd->parent->hwndSelf, 0,
2836                              (LPPOINT)&tempRect, 2 );
2837
2838         if (PtInRect( &tempRect, pt))
2839         {
2840             wParam = 0;
2841
2842             for (ptrWnd = WIN_LockWndPtr(ptrQueryWnd->child); ptrWnd ;WIN_UpdateWndPtr(&ptrWnd,ptrWnd->next))
2843             {
2844                 if( ptrWnd->dwStyle & WS_VISIBLE )
2845                 {
2846                     GetWindowRect( ptrWnd->hwndSelf, &tempRect );
2847                     if (PtInRect( &tempRect, pt )) break;
2848                 }
2849             }
2850
2851             if(ptrWnd)
2852             {
2853                 TRACE_(msg)("hwnd = %04x, %d %d - %d %d\n",
2854                             ptrWnd->hwndSelf, ptrWnd->rectWindow.left, ptrWnd->rectWindow.top,
2855                             ptrWnd->rectWindow.right, ptrWnd->rectWindow.bottom );
2856                 if( !(ptrWnd->dwStyle & WS_DISABLED) )
2857                     bResult = DRAG_QueryUpdate(ptrWnd->hwndSelf, spDragInfo, bNoSend);
2858
2859                 WIN_ReleaseWndPtr(ptrWnd);
2860             }
2861
2862             if(bResult)
2863             {
2864                 WIN_ReleaseWndPtr(ptrQueryWnd);
2865                 return bResult;
2866             }
2867         }
2868         else wParam = 1;
2869         WIN_ReleaseWndPtr(ptrQueryWnd);
2870     }
2871     else wParam = 1;
2872
2873     ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
2874
2875     ptrDragInfo->hScope = hQueryWnd;
2876
2877     if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
2878     else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
2879
2880     if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
2881
2882     return bResult;
2883 }
2884
2885
2886 /*******************************************************************
2887  *              DragDetect (USER.465)
2888  */
2889 BOOL16 WINAPI DragDetect16( HWND16 hWnd, POINT16 pt )
2890 {
2891     POINT pt32;
2892     CONV_POINT16TO32( &pt, &pt32 );
2893     return DragDetect( hWnd, pt32 );
2894 }
2895
2896 /*******************************************************************
2897  *              DragDetect (USER32.@)
2898  */
2899 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
2900 {
2901     MSG msg;
2902     RECT rect;
2903
2904     rect.left = pt.x - wDragWidth;
2905     rect.right = pt.x + wDragWidth;
2906
2907     rect.top = pt.y - wDragHeight;
2908     rect.bottom = pt.y + wDragHeight;
2909
2910     SetCapture(hWnd);
2911
2912     while(1)
2913     {
2914         while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
2915         {
2916             if( msg.message == WM_LBUTTONUP )
2917             {
2918                 ReleaseCapture();
2919                 return 0;
2920             }
2921             if( msg.message == WM_MOUSEMOVE )
2922             {
2923                 POINT tmp;
2924                 tmp.x = LOWORD(msg.lParam);
2925                 tmp.y = HIWORD(msg.lParam);
2926                 if( !PtInRect( &rect, tmp ))
2927                 {
2928                     ReleaseCapture();
2929                     return 1;
2930                 }
2931             }
2932         }
2933         WaitMessage();
2934     }
2935     return 0;
2936 }
2937
2938 /******************************************************************************
2939  *              DragObject (USER.464)
2940  */
2941 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
2942                            HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
2943 {
2944     MSG msg;
2945     LPDRAGINFO16 lpDragInfo;
2946     SEGPTR      spDragInfo;
2947     HCURSOR16   hDragCursor=0, hOldCursor=0, hBummer=0;
2948     HGLOBAL16   hDragInfo  = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
2949     HCURSOR16   hCurrentCursor = 0;
2950     HWND16      hCurrentWnd = 0;
2951
2952     lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
2953     spDragInfo = K32WOWGlobalLock16(hDragInfo);
2954
2955     if( !lpDragInfo || !spDragInfo ) return 0L;
2956
2957     if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
2958     {
2959         GlobalFree16(hDragInfo);
2960         return 0L;
2961     }
2962
2963     if(hCursor)
2964     {
2965         if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
2966         {
2967             GlobalFree16(hDragInfo);
2968             return 0L;
2969         }
2970
2971         if( hDragCursor == hCursor ) hDragCursor = 0;
2972         else hCursor = hDragCursor;
2973
2974         hOldCursor = SetCursor(hDragCursor);
2975     }
2976
2977     lpDragInfo->hWnd   = hWnd;
2978     lpDragInfo->hScope = 0;
2979     lpDragInfo->wFlags = wObj;
2980     lpDragInfo->hList  = szList; /* near pointer! */
2981     lpDragInfo->hOfStruct = hOfStruct;
2982     lpDragInfo->l = 0L; 
2983
2984     SetCapture(hWnd);
2985     ShowCursor( TRUE );
2986
2987     do
2988     {
2989         GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
2990
2991        *(lpDragInfo+1) = *lpDragInfo;
2992
2993         lpDragInfo->pt.x = msg.pt.x;
2994         lpDragInfo->pt.y = msg.pt.y;
2995
2996         /* update DRAGINFO struct */
2997         TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
2998
2999         if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
3000             hCurrentCursor = hCursor;
3001         else
3002         {
3003             hCurrentCursor = hBummer;
3004             lpDragInfo->hScope = 0;
3005         }
3006         if( hCurrentCursor )
3007             SetCursor(hCurrentCursor);
3008
3009         /* send WM_DRAGLOOP */
3010         SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer), 
3011                                           (LPARAM) spDragInfo );
3012         /* send WM_DRAGSELECT or WM_DRAGMOVE */
3013         if( hCurrentWnd != lpDragInfo->hScope )
3014         {
3015             if( hCurrentWnd )
3016                 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0, 
3017                        (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3018                                         HIWORD(spDragInfo)) );
3019             hCurrentWnd = lpDragInfo->hScope;
3020             if( hCurrentWnd )
3021                 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo); 
3022         }
3023         else
3024             if( hCurrentWnd )
3025                 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3026
3027     } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3028
3029     ReleaseCapture();
3030     ShowCursor( FALSE );
3031
3032     if( hCursor )
3033     {
3034         SetCursor( hOldCursor );
3035         if (hDragCursor) DestroyCursor( hDragCursor );
3036     }
3037
3038     if( hCurrentCursor != hBummer ) 
3039         msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT, 
3040                                    (WPARAM16)hWnd, (LPARAM)spDragInfo );
3041     else
3042         msg.lParam = 0;
3043     GlobalFree16(hDragInfo);
3044
3045     return (DWORD)(msg.lParam);
3046 }
3047
3048
3049 /******************************************************************************
3050  *              GetWindowModuleFileNameA (USER32.@)
3051  */
3052 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3053 {
3054     FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3055           hwnd, lpszFileName, cchFileNameMax);
3056     return 0;
3057 }
3058
3059 /******************************************************************************
3060  *              GetWindowModuleFileNameW (USER32.@)
3061  */
3062 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3063 {
3064     FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3065           hwnd, lpszFileName, cchFileNameMax);
3066     return 0;
3067 }