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