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