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