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