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