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