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