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