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