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