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