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