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