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