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