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