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