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