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