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