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