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