Cosmetic fixes.
[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             if (IsWindow(hwnd))
1789                 FIXME( "(%d) not supported on other process window %x\n", offset, hwnd );
1790             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1791             return 0;
1792         }
1793         if (offset == GWL_WNDPROC)
1794         {
1795             SetLastError( ERROR_ACCESS_DENIED );
1796             return 0;
1797         }
1798         SERVER_START_REQ( set_window_info )
1799         {
1800             req->handle = hwnd;
1801             req->flags  = 0;  /* don't set anything, just retrieve */
1802             if (!SERVER_CALL_ERR())
1803             {
1804                 switch(offset)
1805                 {
1806                 case GWL_STYLE:     retvalue = req->style; break;
1807                 case GWL_EXSTYLE:   retvalue = req->ex_style; break;
1808                 case GWL_ID:        retvalue = req->id; break;
1809                 case GWL_HINSTANCE: retvalue = (ULONG_PTR)req->instance; break;
1810                 case GWL_USERDATA:  retvalue = (ULONG_PTR)req->user_data; break;
1811                 default:
1812                     SetLastError( ERROR_INVALID_INDEX );
1813                     break;
1814                 }
1815             }
1816         }
1817         SERVER_END_REQ;
1818         return retvalue;
1819     }
1820
1821     /* now we have a valid wndPtr */
1822
1823     if (offset >= 0)
1824     {
1825         if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1826         {
1827             WARN("Invalid offset %d\n", offset );
1828             WIN_ReleasePtr( wndPtr );
1829             SetLastError( ERROR_INVALID_INDEX );
1830             return 0;
1831         }
1832         /* Special case for dialog window procedure */
1833         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1834             retvalue = (LONG)WINPROC_GetProc( (HWINDOWPROC)retvalue, type );
1835         else
1836             retvalue = *(LONG *)(((char *)wndPtr->wExtra) + offset);
1837         WIN_ReleasePtr( wndPtr );
1838         return retvalue;
1839     }
1840
1841     switch(offset)
1842     {
1843     case GWL_USERDATA:   retvalue = wndPtr->userdata; break;
1844     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
1845     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
1846     case GWL_ID:         retvalue = (LONG)wndPtr->wIDmenu; break;
1847     case GWL_WNDPROC:    retvalue = (LONG)WINPROC_GetProc( wndPtr->winproc, type ); break;
1848     case GWL_HINSTANCE:  retvalue = wndPtr->hInstance; break;
1849     default:
1850         WARN("Unknown offset %d\n", offset );
1851         SetLastError( ERROR_INVALID_INDEX );
1852         break;
1853     }
1854     WIN_ReleasePtr(wndPtr);
1855     return retvalue;
1856 }
1857
1858
1859 /**********************************************************************
1860  *           WIN_SetWindowLong
1861  *
1862  * Helper function for SetWindowLong().
1863  *
1864  * 0 is the failure code. However, in the case of failure SetLastError
1865  * must be set to distinguish between a 0 return value and a failure.
1866  */
1867 static LONG WIN_SetWindowLong( HWND hwnd, INT offset, LONG newval,
1868                                WINDOWPROCTYPE type )
1869 {
1870     LONG retval = 0;
1871     WND *wndPtr;
1872
1873     TRACE( "%x %d %lx %x\n", hwnd, offset, newval, type );
1874
1875     if (!WIN_IsCurrentProcess( hwnd ))
1876     {
1877         if (offset == GWL_WNDPROC)
1878         {
1879             SetLastError( ERROR_ACCESS_DENIED );
1880             return 0;
1881         }
1882         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, offset, newval );
1883     }
1884
1885     wndPtr = WIN_GetPtr( hwnd );
1886
1887     if (offset >= 0)
1888     {
1889         LONG *ptr = (LONG *)(((char *)wndPtr->wExtra) + offset);
1890         if (offset > wndPtr->cbWndExtra - sizeof(LONG))
1891         {
1892             WARN("Invalid offset %d\n", offset );
1893             WIN_ReleasePtr( wndPtr );
1894             SetLastError( ERROR_INVALID_INDEX );
1895             return 0;
1896         }
1897         /* Special case for dialog window procedure */
1898         if ((offset == DWL_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG))
1899         {
1900             retval = (LONG)WINPROC_GetProc( (HWINDOWPROC)*ptr, type );
1901             WINPROC_SetProc( (HWINDOWPROC *)ptr, (WNDPROC16)newval,
1902                              type, WIN_PROC_WINDOW );
1903             WIN_ReleasePtr( wndPtr );
1904             return retval;
1905         }
1906         retval = *ptr;
1907         *ptr = newval;
1908         WIN_ReleasePtr( wndPtr );
1909     }
1910     else
1911     {
1912         STYLESTRUCT style;
1913         BOOL ok;
1914
1915         /* first some special cases */
1916         switch( offset )
1917         {
1918         case GWL_STYLE:
1919         case GWL_EXSTYLE:
1920             style.styleOld = wndPtr->dwStyle;
1921             style.styleNew = newval;
1922             WIN_ReleasePtr( wndPtr );
1923             SendMessageW( hwnd, WM_STYLECHANGING, offset, (LPARAM)&style );
1924             if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
1925             newval = style.styleNew;
1926             break;
1927         case GWL_HWNDPARENT:
1928             WIN_ReleasePtr( wndPtr );
1929             return (LONG)SetParent( hwnd, (HWND)newval );
1930         case GWL_WNDPROC:
1931             retval = (LONG)WINPROC_GetProc( wndPtr->winproc, type );
1932             WINPROC_SetProc( &wndPtr->winproc, (WNDPROC16)newval,
1933                              type, WIN_PROC_WINDOW );
1934             WIN_ReleasePtr( wndPtr );
1935             return retval;
1936         case GWL_ID:
1937         case GWL_HINSTANCE:
1938         case GWL_USERDATA:
1939             break;
1940         default:
1941             WIN_ReleasePtr( wndPtr );
1942             WARN("Invalid offset %d\n", offset );
1943             SetLastError( ERROR_INVALID_INDEX );
1944             return 0;
1945         }
1946
1947         SERVER_START_REQ( set_window_info )
1948         {
1949             req->handle = hwnd;
1950             switch(offset)
1951             {
1952             case GWL_STYLE:
1953                 req->flags = SET_WIN_STYLE;
1954                 req->style = newval;
1955                 break;
1956             case GWL_EXSTYLE:
1957                 req->flags = SET_WIN_EXSTYLE;
1958                 req->ex_style = newval;
1959                 break;
1960             case GWL_ID:
1961                 req->flags = SET_WIN_ID;
1962                 req->id = newval;
1963                 break;
1964             case GWL_HINSTANCE:
1965                 req->flags = SET_WIN_INSTANCE;
1966                 req->instance = (void *)newval;
1967                 break;
1968             case GWL_USERDATA:
1969                 req->flags = SET_WIN_USERDATA;
1970                 req->user_data = (void *)newval;
1971                 break;
1972             }
1973             if ((ok = !SERVER_CALL_ERR()))
1974             {
1975                 switch(offset)
1976                 {
1977                 case GWL_STYLE:
1978                     wndPtr->dwStyle = newval;
1979                     retval = req->old_style;
1980                     break;
1981                 case GWL_EXSTYLE:
1982                     wndPtr->dwExStyle = newval;
1983                     retval = req->old_ex_style;
1984                     break;
1985                 case GWL_ID:
1986                     wndPtr->wIDmenu = newval;
1987                     retval = req->old_id;
1988                     break;
1989                 case GWL_HINSTANCE:
1990                     wndPtr->hInstance = newval;
1991                     retval = (HINSTANCE)req->old_instance;
1992                     break;
1993                 case GWL_USERDATA:
1994                     wndPtr->userdata = newval;
1995                     retval = (ULONG_PTR)req->old_user_data;
1996                     break;
1997                 }
1998             }
1999         }
2000         SERVER_END_REQ;
2001         WIN_ReleasePtr( wndPtr );
2002
2003         if (!ok) return 0;
2004
2005         if (offset == GWL_STYLE && USER_Driver.pSetWindowStyle)
2006             USER_Driver.pSetWindowStyle( hwnd, retval );
2007
2008         if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2009             SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2010
2011     }
2012     return retval;
2013 }
2014
2015
2016 /**********************************************************************
2017  *              GetWindowLong (USER.135)
2018  */
2019 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2020 {
2021     return WIN_GetWindowLong( WIN_Handle32(hwnd), offset, WIN_PROC_16 );
2022 }
2023
2024
2025 /**********************************************************************
2026  *              GetWindowLongA (USER32.@)
2027  */
2028 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2029 {
2030     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32A );
2031 }
2032
2033
2034 /**********************************************************************
2035  *              GetWindowLongW (USER32.@)
2036  */
2037 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2038 {
2039     return WIN_GetWindowLong( hwnd, offset, WIN_PROC_32W );
2040 }
2041
2042
2043 /**********************************************************************
2044  *              SetWindowLong (USER.136)
2045  */
2046 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2047 {
2048     return WIN_SetWindowLong( WIN_Handle32(hwnd), offset, newval, WIN_PROC_16 );
2049 }
2050
2051
2052 /**********************************************************************
2053  *              SetWindowLongA (USER32.@)
2054  */
2055 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2056 {
2057     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32A );
2058 }
2059
2060
2061 /**********************************************************************
2062  *              SetWindowLongW (USER32.@) Set window attribute
2063  *
2064  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2065  * value in a window's extra memory.
2066  *
2067  * The _hwnd_ parameter specifies the window.  is the handle to a
2068  * window that has extra memory. The _newval_ parameter contains the
2069  * new attribute or extra memory value.  If positive, the _offset_
2070  * parameter is the byte-addressed location in the window's extra
2071  * memory to set.  If negative, _offset_ specifies the window
2072  * attribute to set, and should be one of the following values:
2073  *
2074  * GWL_EXSTYLE      The window's extended window style
2075  *
2076  * GWL_STYLE        The window's window style.
2077  *
2078  * GWL_WNDPROC      Pointer to the window's window procedure.
2079  *
2080  * GWL_HINSTANCE    The window's pplication instance handle.
2081  *
2082  * GWL_ID           The window's identifier.
2083  *
2084  * GWL_USERDATA     The window's user-specified data.
2085  *
2086  * If the window is a dialog box, the _offset_ parameter can be one of
2087  * the following values:
2088  *
2089  * DWL_DLGPROC      The address of the window's dialog box procedure.
2090  *
2091  * DWL_MSGRESULT    The return value of a message
2092  *                  that the dialog box procedure processed.
2093  *
2094  * DWL_USER         Application specific information.
2095  *
2096  * RETURNS
2097  *
2098  * If successful, returns the previous value located at _offset_. Otherwise,
2099  * returns 0.
2100  *
2101  * NOTES
2102  *
2103  * Extra memory for a window class is specified by a nonzero cbWndExtra
2104  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2105  * time of class creation.
2106  *
2107  * Using GWL_WNDPROC to set a new window procedure effectively creates
2108  * a window subclass. Use CallWindowProc() in the new windows procedure
2109  * to pass messages to the superclass's window procedure.
2110  *
2111  * The user data is reserved for use by the application which created
2112  * the window.
2113  *
2114  * Do not use GWL_STYLE to change the window's WS_DISABLE style;
2115  * instead, call the EnableWindow() function to change the window's
2116  * disabled state.
2117  *
2118  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2119  * SetParent() instead.
2120  *
2121  * Win95:
2122  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2123  * it sends WM_STYLECHANGING before changing the settings
2124  * and WM_STYLECHANGED afterwards.
2125  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2126  */
2127 LONG WINAPI SetWindowLongW(
2128     HWND hwnd,  /* [in] window to alter */
2129     INT offset, /* [in] offset, in bytes, of location to alter */
2130     LONG newval /* [in] new value of location */
2131 ) {
2132     return WIN_SetWindowLong( hwnd, offset, newval, WIN_PROC_32W );
2133 }
2134
2135
2136 /*******************************************************************
2137  *              GetWindowTextA (USER32.@)
2138  */
2139 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2140 {
2141     return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount,
2142                                   (LPARAM)lpString );
2143 }
2144
2145 /*******************************************************************
2146  *              InternalGetWindowText (USER32.@)
2147  */
2148 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2149 {
2150     WND *win = WIN_FindWndPtr( hwnd );
2151     if (!win) return 0;
2152     if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2153     else lpString[0] = 0;
2154     WIN_ReleaseWndPtr( win );
2155     return strlenW(lpString);
2156 }
2157
2158
2159 /*******************************************************************
2160  *              GetWindowTextW (USER32.@)
2161  */
2162 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2163 {
2164     return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount,
2165                                   (LPARAM)lpString );
2166 }
2167
2168
2169 /*******************************************************************
2170  *              SetWindowText  (USER32.@)
2171  *              SetWindowTextA (USER32.@)
2172  */
2173 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2174 {
2175     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2176 }
2177
2178
2179 /*******************************************************************
2180  *              SetWindowTextW (USER32.@)
2181  */
2182 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2183 {
2184     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2185 }
2186
2187
2188 /*******************************************************************
2189  *              GetWindowTextLengthA (USER32.@)
2190  */
2191 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2192 {
2193     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2194 }
2195
2196 /*******************************************************************
2197  *              GetWindowTextLengthW (USER32.@)
2198  */
2199 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2200 {
2201     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2202 }
2203
2204
2205 /*******************************************************************
2206  *              IsWindow (USER32.@)
2207  */
2208 BOOL WINAPI IsWindow( HWND hwnd )
2209 {
2210     WND *ptr;
2211     BOOL ret;
2212
2213     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2214
2215     if (ptr != WND_OTHER_PROCESS)
2216     {
2217         WIN_ReleasePtr( ptr );
2218         return TRUE;
2219     }
2220
2221     /* check other processes */
2222     SERVER_START_REQ( get_window_info )
2223     {
2224         req->handle = hwnd;
2225         ret = !SERVER_CALL_ERR();
2226     }
2227     SERVER_END_REQ;
2228     return ret;
2229 }
2230
2231
2232 /***********************************************************************
2233  *              GetWindowThreadProcessId (USER32.@)
2234  */
2235 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2236 {
2237     WND *ptr;
2238     DWORD tid = 0;
2239
2240     if (!(ptr = WIN_GetPtr( hwnd )))
2241     {
2242         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2243         return 0;
2244     }
2245
2246     if (ptr != WND_OTHER_PROCESS)
2247     {
2248         /* got a valid window */
2249         tid = ptr->tid;
2250         if (process) *process = GetCurrentProcessId();
2251         WIN_ReleasePtr( ptr );
2252         return tid;
2253     }
2254
2255     /* check other processes */
2256     SERVER_START_REQ( get_window_info )
2257     {
2258         req->handle = hwnd;
2259         if (!SERVER_CALL_ERR())
2260         {
2261             tid = (DWORD)req->tid;
2262             if (process) *process = (DWORD)req->pid;
2263         }
2264     }
2265     SERVER_END_REQ;
2266     return tid;
2267 }
2268
2269
2270 /*****************************************************************
2271  *              GetParent (USER32.@)
2272  */
2273 HWND WINAPI GetParent( HWND hwnd )
2274 {
2275     WND *wndPtr;
2276     HWND retvalue = 0;
2277
2278     if (!(wndPtr = WIN_GetPtr( hwnd )))
2279     {
2280         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2281         return 0;
2282     }
2283     if (wndPtr == WND_OTHER_PROCESS)
2284     {
2285         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2286         if (style & (WS_POPUP | WS_CHILD))
2287         {
2288             SERVER_START_REQ( get_window_tree )
2289             {
2290                 req->handle = hwnd;
2291                 if (!SERVER_CALL_ERR())
2292                 {
2293                     if (style & WS_CHILD) retvalue = req->parent;
2294                     else retvalue = req->owner;
2295                 }
2296             }
2297             SERVER_END_REQ;
2298         }
2299     }
2300     else
2301     {
2302         if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2303         else if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2304         WIN_ReleasePtr( wndPtr );
2305     }
2306     return retvalue;
2307 }
2308
2309
2310 /*****************************************************************
2311  *              GetAncestor (USER32.@)
2312  */
2313 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2314 {
2315     WND *win;
2316     HWND ret = 0;
2317     size_t size;
2318
2319     for (;;)
2320     {
2321         if (!(win = WIN_GetPtr( hwnd )))
2322         {
2323             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2324             return 0;
2325         }
2326         if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
2327         ret = win->parent;
2328         WIN_ReleasePtr( win );
2329         if (type == GA_PARENT) return ret;
2330         if (!ret || ret == GetDesktopWindow())
2331         {
2332             ret = hwnd;  /* if ret is the desktop, hwnd is the root ancestor */
2333             goto done;
2334         }
2335         hwnd = ret;  /* restart with parent as hwnd */
2336     }
2337
2338     size = (type == GA_PARENT) ? sizeof(user_handle_t) : REQUEST_MAX_VAR_SIZE;
2339
2340     SERVER_START_VAR_REQ( get_window_parents, size )
2341     {
2342         req->handle = hwnd;
2343         if (!SERVER_CALL())
2344         {
2345             user_handle_t *data = server_data_ptr(req);
2346             int count = server_data_size(req) / sizeof(*data);
2347             if (count)
2348             {
2349                 switch(type)
2350                 {
2351                 case GA_PARENT:
2352                     ret = data[0];
2353                     break;
2354                 case GA_ROOT:
2355                 case GA_ROOTOWNER:
2356                     if (count > 1) ret = data[count - 2];  /* get the one before the desktop */
2357                     else ret = WIN_GetFullHandle( hwnd );
2358                     break;
2359                 }
2360             }
2361         }
2362     }
2363     SERVER_END_VAR_REQ;
2364
2365  done:
2366     if (ret && type == GA_ROOTOWNER)
2367     {
2368         for (;;)
2369         {
2370             HWND owner = GetWindow( ret, GW_OWNER );
2371             if (!owner) break;
2372             ret = owner;
2373         }
2374     }
2375     return ret;
2376 }
2377
2378
2379 /*****************************************************************
2380  *              SetParent (USER32.@)
2381  */
2382 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2383 {
2384     WND *wndPtr;
2385     HWND retvalue, full_handle;
2386     BOOL was_visible;
2387
2388     if (!parent) parent = GetDesktopWindow();
2389     else parent = WIN_GetFullHandle( parent );
2390
2391     if (!IsWindow( parent ))
2392     {
2393         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2394         return 0;
2395     }
2396
2397     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2398         return SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2399
2400     hwnd = full_handle;
2401
2402     if (USER_Driver.pSetParent)
2403         return USER_Driver.pSetParent( hwnd, parent );
2404
2405     /* Windows hides the window first, then shows it again
2406      * including the WM_SHOWWINDOW messages and all */
2407     was_visible = ShowWindow( hwnd, SW_HIDE );
2408
2409     if (!IsWindow( parent )) return 0;
2410     if (!(wndPtr = WIN_GetPtr(hwnd)) || wndPtr == WND_OTHER_PROCESS) return 0;
2411
2412     retvalue = wndPtr->parent;  /* old parent */
2413     if (parent != retvalue)
2414     {
2415         WIN_LinkWindow( hwnd, parent, HWND_TOP );
2416
2417         if (parent != GetDesktopWindow()) /* a child window */
2418         {
2419             if (!(wndPtr->dwStyle & WS_CHILD))
2420             {
2421                 HMENU menu = (HMENU)SetWindowLongW( hwnd, GWL_ID, 0 );
2422                 if (menu) DestroyMenu( menu );
2423             }
2424         }
2425     }
2426     WIN_ReleasePtr( wndPtr );
2427
2428     /* SetParent additionally needs to make hwnd the topmost window
2429        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2430        WM_WINDOWPOSCHANGED notification messages.
2431     */
2432     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2433                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2434     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2435      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2436     return retvalue;
2437 }
2438
2439
2440 /*******************************************************************
2441  *              IsChild (USER32.@)
2442  */
2443 BOOL WINAPI IsChild( HWND parent, HWND child )
2444 {
2445     HWND *list = WIN_ListParents( child );
2446     int i;
2447     BOOL ret;
2448
2449     if (!list) return FALSE;
2450     parent = WIN_GetFullHandle( parent );
2451     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2452     ret = (list[i] != 0);
2453     HeapFree( GetProcessHeap(), 0, list );
2454     return ret;
2455 }
2456
2457
2458 /***********************************************************************
2459  *              IsWindowVisible (USER32.@)
2460  */
2461 BOOL WINAPI IsWindowVisible( HWND hwnd )
2462 {
2463     HWND *list;
2464     BOOL retval;
2465     int i;
2466
2467     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2468     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2469     for (i = 0; list[i]; i++)
2470         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2471     retval = !list[i];
2472     HeapFree( GetProcessHeap(), 0, list );
2473     return retval;
2474 }
2475
2476
2477 /***********************************************************************
2478  *           WIN_IsWindowDrawable
2479  *
2480  * hwnd is drawable when it is visible, all parents are not
2481  * minimized, and it is itself not minimized unless we are
2482  * trying to draw its default class icon.
2483  */
2484 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2485 {
2486     HWND *list;
2487     BOOL retval;
2488     int i;
2489     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2490
2491     if (!(style & WS_VISIBLE)) return FALSE;
2492     if ((style & WS_MINIMIZE) && icon && GetClassLongA( hwnd, GCL_HICON ))  return FALSE;
2493
2494     if (!(list = WIN_ListParents( hwnd ))) return TRUE;
2495     for (i = 0; list[i]; i++)
2496         if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2497             break;
2498     retval = !list[i];
2499     HeapFree( GetProcessHeap(), 0, list );
2500     return retval;
2501 }
2502
2503
2504 /*******************************************************************
2505  *              GetTopWindow (USER32.@)
2506  */
2507 HWND WINAPI GetTopWindow( HWND hwnd )
2508 {
2509     if (!hwnd) hwnd = GetDesktopWindow();
2510     return GetWindow( hwnd, GW_CHILD );
2511 }
2512
2513
2514 /*******************************************************************
2515  *              GetWindow (USER32.@)
2516  */
2517 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2518 {
2519     HWND retval = 0;
2520
2521     if (rel == GW_OWNER)  /* this one may be available locally */
2522     {
2523         WND *wndPtr = WIN_GetPtr( hwnd );
2524         if (!wndPtr)
2525         {
2526             SetLastError( ERROR_INVALID_HANDLE );
2527             return 0;
2528         }
2529         if (wndPtr != WND_OTHER_PROCESS)
2530         {
2531             retval = wndPtr->owner;
2532             WIN_ReleasePtr( wndPtr );
2533             return retval;
2534         }
2535         /* else fall through to server call */
2536     }
2537
2538     SERVER_START_REQ( get_window_tree )
2539     {
2540         req->handle = hwnd;
2541         if (!SERVER_CALL_ERR())
2542         {
2543             switch(rel)
2544             {
2545             case GW_HWNDFIRST:
2546                 retval = req->first_sibling;
2547                 break;
2548             case GW_HWNDLAST:
2549                 retval = req->last_sibling;
2550                 break;
2551             case GW_HWNDNEXT:
2552                 retval = req->next_sibling;
2553                 break;
2554             case GW_HWNDPREV:
2555                 retval = req->prev_sibling;
2556                 break;
2557             case GW_OWNER:
2558                 retval = req->owner;
2559                 break;
2560             case GW_CHILD:
2561                 retval = req->first_child;
2562                 break;
2563             }
2564         }
2565     }
2566     SERVER_END_REQ;
2567     return retval;
2568 }
2569
2570
2571 /***********************************************************************
2572  *           WIN_InternalShowOwnedPopups
2573  *
2574  * Internal version of ShowOwnedPopups; Wine functions should use this
2575  * to avoid interfering with application calls to ShowOwnedPopups
2576  * and to make sure the application can't prevent showing/hiding.
2577  *
2578  * Set unmanagedOnly to TRUE to show/hide unmanaged windows only.
2579  *
2580  */
2581
2582 BOOL WIN_InternalShowOwnedPopups( HWND owner, BOOL fShow, BOOL unmanagedOnly )
2583 {
2584     int count = 0;
2585     WND *pWnd;
2586     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2587
2588     if (!win_array) return TRUE;
2589
2590     /*
2591      * Show windows Lowest first, Highest last to preserve Z-Order
2592      */
2593     while (win_array[count]) count++;
2594     while (--count >= 0)
2595     {
2596         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2597         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2598
2599         if (pWnd->dwStyle & WS_POPUP)
2600         {
2601             if (fShow)
2602             {
2603                 /* check in window was flagged for showing in previous WIN_InternalShowOwnedPopups call */
2604                 if (pWnd->flags & WIN_NEEDS_INTERNALSOP)
2605                 {
2606                     /*
2607                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2608                      */
2609                     ShowWindow(pWnd->hwndSelf,SW_SHOW);
2610                     pWnd->flags &= ~WIN_NEEDS_INTERNALSOP; /* remove the flag */
2611                 }
2612             }
2613             else
2614             {
2615                 if ( IsWindowVisible(pWnd->hwndSelf) &&                   /* hide only if window is visible */
2616                      !( pWnd->flags & WIN_NEEDS_INTERNALSOP ) &&          /* don't hide if previous call already did it */
2617                      !( unmanagedOnly && (pWnd->dwExStyle & WS_EX_MANAGED) ) ) /* don't hide managed windows if unmanagedOnly is TRUE */
2618                 {
2619                     /*
2620                      * Call ShowWindow directly because an application can intercept WM_SHOWWINDOW messages
2621                      */
2622                     ShowWindow(pWnd->hwndSelf,SW_HIDE);
2623                     /* flag the window for showing on next WIN_InternalShowOwnedPopups call */
2624                     pWnd->flags |= WIN_NEEDS_INTERNALSOP;
2625                 }
2626             }
2627         }
2628         WIN_ReleaseWndPtr( pWnd );
2629     }
2630     HeapFree( GetProcessHeap(), 0, win_array );
2631
2632     return TRUE;
2633 }
2634
2635 /*******************************************************************
2636  *              ShowOwnedPopups (USER32.@)
2637  */
2638 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2639 {
2640     int count = 0;
2641     WND *pWnd;
2642     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2643
2644     if (!win_array) return TRUE;
2645
2646     while (win_array[count]) count++;
2647     while (--count >= 0)
2648     {
2649         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2650         if (!(pWnd = WIN_FindWndPtr( win_array[count] ))) continue;
2651
2652         if (pWnd->dwStyle & WS_POPUP)
2653         {
2654             if (fShow)
2655             {
2656                 if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2657                 {
2658                     /* In Windows, ShowOwnedPopups(TRUE) generates
2659                      * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2660                      * regardless of the state of the owner
2661                      */
2662                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_SHOW, SW_PARENTOPENING);
2663                     pWnd->flags &= ~WIN_NEEDS_SHOW_OWNEDPOPUP;
2664                 }
2665             }
2666             else
2667             {
2668                 if (IsWindowVisible(pWnd->hwndSelf))
2669                 {
2670                     /* In Windows, ShowOwnedPopups(FALSE) generates
2671                      * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2672                      * regardless of the state of the owner
2673                      */
2674                     SendMessageA(pWnd->hwndSelf, WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2675                     pWnd->flags |= WIN_NEEDS_SHOW_OWNEDPOPUP;
2676                 }
2677             }
2678         }
2679         WIN_ReleaseWndPtr( pWnd );
2680     }
2681     HeapFree( GetProcessHeap(), 0, win_array );
2682     return TRUE;
2683 }
2684
2685
2686 /*******************************************************************
2687  *              GetLastActivePopup (USER32.@)
2688  */
2689 HWND WINAPI GetLastActivePopup( HWND hwnd )
2690 {
2691     HWND retval;
2692     WND *wndPtr =WIN_FindWndPtr(hwnd);
2693     if (!wndPtr) return hwnd;
2694     retval = wndPtr->hwndLastActive;
2695     if (!IsWindow( retval )) retval = wndPtr->hwndSelf;
2696     WIN_ReleaseWndPtr(wndPtr);
2697     return retval;
2698 }
2699
2700
2701 /*******************************************************************
2702  *           WIN_ListParents
2703  *
2704  * Build an array of all parents of a given window, starting with
2705  * the immediate parent. The array must be freed with HeapFree.
2706  * Returns NULL if window is a top-level window.
2707  */
2708 HWND *WIN_ListParents( HWND hwnd )
2709 {
2710     WND *win;
2711     HWND current, *list;
2712     int pos = 0, size = 16, count = 0;
2713
2714     if (!(list = HeapAlloc( GetProcessHeap(), 0, size * sizeof(HWND) ))) return NULL;
2715
2716     current = hwnd;
2717     for (;;)
2718     {
2719         if (!(win = WIN_GetPtr( current ))) goto empty;
2720         if (win == WND_OTHER_PROCESS) break;  /* need to do it the hard way */
2721         list[pos] = win->parent;
2722         WIN_ReleasePtr( win );
2723         if (!(current = list[pos]))
2724         {
2725             if (!pos) goto empty;
2726             return list;
2727         }
2728         if (++pos == size - 1)
2729         {
2730             /* need to grow the list */
2731             HWND *new_list = HeapReAlloc( GetProcessHeap(), 0, list, (size+16) * sizeof(HWND) );
2732             if (!new_list) goto empty;
2733             list = new_list;
2734             size += 16;
2735         }
2736     }
2737
2738     /* at least one parent belongs to another process, have to query the server */
2739     SERVER_START_VAR_REQ( get_window_parents, REQUEST_MAX_VAR_SIZE )
2740     {
2741         req->handle = hwnd;
2742         if (!SERVER_CALL())
2743         {
2744             user_handle_t *data = server_data_ptr(req);
2745             count = server_data_size(req) / sizeof(*data);
2746             if (count)
2747             {
2748                 HWND *new_list = HeapReAlloc( GetProcessHeap(), 0,
2749                                               list, (count + 1) * sizeof(HWND) );
2750                 if (new_list)
2751                 {
2752                     list = new_list;
2753                     for (pos = 0; pos < count; pos++) list[pos] = data[pos];
2754                     list[pos] = 0;
2755                 }
2756                 else count = 0;
2757             }
2758         }
2759     }
2760     SERVER_END_VAR_REQ;
2761     if (count) return list;
2762
2763  empty:
2764     HeapFree( GetProcessHeap(), 0, list );
2765     return NULL;
2766 }
2767
2768
2769 /*******************************************************************
2770  *           WIN_ListChildren
2771  *
2772  * Build an array of the children of a given window. The array must be
2773  * freed with HeapFree. Returns NULL when no windows are found.
2774  */
2775 HWND *WIN_ListChildren( HWND hwnd )
2776 {
2777     return list_window_children( hwnd, 0, 0 );
2778 }
2779
2780
2781 /*******************************************************************
2782  *              EnumWindows (USER32.@)
2783  */
2784 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2785 {
2786     HWND *list;
2787     BOOL ret = TRUE;
2788     int i, iWndsLocks;
2789
2790     /* We have to build a list of all windows first, to avoid */
2791     /* unpleasant side-effects, for instance if the callback */
2792     /* function changes the Z-order of the windows.          */
2793
2794     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return FALSE;
2795
2796     /* Now call the callback function for every window */
2797
2798     iWndsLocks = WIN_SuspendWndsLock();
2799     for (i = 0; list[i]; i++)
2800     {
2801         /* Make sure that the window still exists */
2802         if (!IsWindow( list[i] )) continue;
2803         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2804     }
2805     WIN_RestoreWndsLock(iWndsLocks);
2806     HeapFree( GetProcessHeap(), 0, list );
2807     return ret;
2808 }
2809
2810
2811 /**********************************************************************
2812  *              EnumTaskWindows16   (USER.225)
2813  */
2814 BOOL16 WINAPI EnumTaskWindows16( HTASK16 hTask, WNDENUMPROC16 func,
2815                                  LPARAM lParam )
2816 {
2817     TDB *tdb = TASK_GetPtr( hTask );
2818     if (!tdb) return FALSE;
2819     return EnumThreadWindows( (DWORD)tdb->teb->tid, (WNDENUMPROC)func, lParam );
2820 }
2821
2822
2823 /**********************************************************************
2824  *              EnumThreadWindows (USER32.@)
2825  */
2826 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2827 {
2828     HWND *list;
2829     int i, iWndsLocks;
2830
2831     if (!(list = list_window_children( GetDesktopWindow(), 0, GetCurrentThreadId() )))
2832         return FALSE;
2833
2834     /* Now call the callback function for every window */
2835
2836     iWndsLocks = WIN_SuspendWndsLock();
2837     for (i = 0; list[i]; i++)
2838         if (!func( list[i], lParam )) break;
2839     WIN_RestoreWndsLock(iWndsLocks);
2840     HeapFree( GetProcessHeap(), 0, list );
2841     return TRUE;
2842 }
2843
2844
2845 /**********************************************************************
2846  *           WIN_EnumChildWindows
2847  *
2848  * Helper function for EnumChildWindows().
2849  */
2850 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2851 {
2852     HWND *childList;
2853     BOOL ret = FALSE;
2854
2855     for ( ; *list; list++)
2856     {
2857         /* Make sure that the window still exists */
2858         if (!IsWindow( *list )) continue;
2859         /* skip owned windows */
2860         if (GetWindow( *list, GW_OWNER )) continue;
2861         /* Build children list first */
2862         childList = WIN_ListChildren( *list );
2863
2864         ret = func( *list, lParam );
2865
2866         if (childList)
2867         {
2868             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2869             HeapFree( GetProcessHeap(), 0, childList );
2870         }
2871         if (!ret) return FALSE;
2872     }
2873     return TRUE;
2874 }
2875
2876
2877 /**********************************************************************
2878  *              EnumChildWindows (USER32.@)
2879  */
2880 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2881 {
2882     HWND *list;
2883     int iWndsLocks;
2884
2885     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2886     iWndsLocks = WIN_SuspendWndsLock();
2887     WIN_EnumChildWindows( list, func, lParam );
2888     WIN_RestoreWndsLock(iWndsLocks);
2889     HeapFree( GetProcessHeap(), 0, list );
2890     return TRUE;
2891 }
2892
2893
2894 /*******************************************************************
2895  *              AnyPopup (USER.52)
2896  */
2897 BOOL16 WINAPI AnyPopup16(void)
2898 {
2899     return AnyPopup();
2900 }
2901
2902
2903 /*******************************************************************
2904  *              AnyPopup (USER32.@)
2905  */
2906 BOOL WINAPI AnyPopup(void)
2907 {
2908     int i;
2909     BOOL retvalue;
2910     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2911
2912     if (!list) return FALSE;
2913     for (i = 0; list[i]; i++)
2914     {
2915         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2916     }
2917     retvalue = (list[i] != 0);
2918     HeapFree( GetProcessHeap(), 0, list );
2919     return retvalue;
2920 }
2921
2922
2923 /*******************************************************************
2924  *              FlashWindow (USER32.@)
2925  */
2926 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2927 {
2928     WND *wndPtr = WIN_FindWndPtr(hWnd);
2929
2930     TRACE("%04x\n", hWnd);
2931
2932     if (!wndPtr) return FALSE;
2933     hWnd = wndPtr->hwndSelf;  /* make it a full handle */
2934
2935     if (wndPtr->dwStyle & WS_MINIMIZE)
2936     {
2937         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2938         {
2939             HDC hDC = GetDC(hWnd);
2940
2941             if (!SendMessageW( hWnd, WM_ERASEBKGND, (WPARAM16)hDC, 0 ))
2942                 wndPtr->flags |= WIN_NEEDS_ERASEBKGND;
2943
2944             ReleaseDC( hWnd, hDC );
2945             wndPtr->flags |= WIN_NCACTIVATED;
2946         }
2947         else
2948         {
2949             RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2950             wndPtr->flags &= ~WIN_NCACTIVATED;
2951         }
2952         WIN_ReleaseWndPtr(wndPtr);
2953         return TRUE;
2954     }
2955     else
2956     {
2957         WPARAM16 wparam;
2958         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2959         else wparam = (hWnd == GetActiveWindow());
2960
2961         WIN_ReleaseWndPtr(wndPtr);
2962         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2963         return wparam;
2964     }
2965 }
2966
2967
2968 /*******************************************************************
2969  *              GetWindowContextHelpId (USER32.@)
2970  */
2971 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
2972 {
2973     DWORD retval;
2974     WND *wnd = WIN_FindWndPtr( hwnd );
2975     if (!wnd) return 0;
2976     retval = wnd->helpContext;
2977     WIN_ReleaseWndPtr(wnd);
2978     return retval;
2979 }
2980
2981
2982 /*******************************************************************
2983  *              SetWindowContextHelpId (USER32.@)
2984  */
2985 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
2986 {
2987     WND *wnd = WIN_FindWndPtr( hwnd );
2988     if (!wnd) return FALSE;
2989     wnd->helpContext = id;
2990     WIN_ReleaseWndPtr(wnd);
2991     return TRUE;
2992 }
2993
2994
2995 /*******************************************************************
2996  *                      DRAG_QueryUpdate
2997  *
2998  * recursively find a child that contains spDragInfo->pt point
2999  * and send WM_QUERYDROPOBJECT
3000  */
3001 BOOL16 DRAG_QueryUpdate( HWND hQueryWnd, SEGPTR spDragInfo, BOOL bNoSend )
3002 {
3003     BOOL16 wParam, bResult = 0;
3004     POINT pt;
3005     LPDRAGINFO16 ptrDragInfo = MapSL(spDragInfo);
3006     RECT tempRect;
3007
3008     if (!ptrDragInfo) return FALSE;
3009
3010     CONV_POINT16TO32( &ptrDragInfo->pt, &pt );
3011
3012     GetWindowRect(hQueryWnd,&tempRect);
3013
3014     if( !PtInRect(&tempRect,pt) || !IsWindowEnabled(hQueryWnd)) return FALSE;
3015
3016     if (!IsIconic( hQueryWnd ))
3017     {
3018         GetClientRect( hQueryWnd, &tempRect );
3019         MapWindowPoints( hQueryWnd, 0, (LPPOINT)&tempRect, 2 );
3020
3021         if (PtInRect( &tempRect, pt))
3022         {
3023             int i;
3024             HWND *list = WIN_ListChildren( hQueryWnd );
3025
3026             wParam = 0;
3027
3028             if (list)
3029             {
3030                 for (i = 0; list[i]; i++)
3031                 {
3032                     if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)
3033                     {
3034                         GetWindowRect( list[i], &tempRect );
3035                         if (PtInRect( &tempRect, pt )) break;
3036                     }
3037                 }
3038                 if (list[i])
3039                 {
3040                     if (IsWindowEnabled( list[i] ))
3041                         bResult = DRAG_QueryUpdate( list[i], spDragInfo, bNoSend );
3042                 }
3043                 HeapFree( GetProcessHeap(), 0, list );
3044             }
3045             if(bResult) return bResult;
3046         }
3047         else wParam = 1;
3048     }
3049     else wParam = 1;
3050
3051     ScreenToClient16(hQueryWnd,&ptrDragInfo->pt);
3052
3053     ptrDragInfo->hScope = hQueryWnd;
3054
3055     if (bNoSend) bResult = (GetWindowLongA( hQueryWnd, GWL_EXSTYLE ) & WS_EX_ACCEPTFILES) != 0;
3056     else bResult = SendMessage16( hQueryWnd, WM_QUERYDROPOBJECT, (WPARAM16)wParam, spDragInfo );
3057
3058     if( !bResult ) CONV_POINT32TO16( &pt, &ptrDragInfo->pt );
3059
3060     return bResult;
3061 }
3062
3063
3064 /*******************************************************************
3065  *              DragDetect (USER32.@)
3066  */
3067 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3068 {
3069     MSG msg;
3070     RECT rect;
3071
3072     rect.left = pt.x - wDragWidth;
3073     rect.right = pt.x + wDragWidth;
3074
3075     rect.top = pt.y - wDragHeight;
3076     rect.bottom = pt.y + wDragHeight;
3077
3078     SetCapture(hWnd);
3079
3080     while(1)
3081     {
3082         while(PeekMessageA(&msg ,0 ,WM_MOUSEFIRST ,WM_MOUSELAST ,PM_REMOVE))
3083         {
3084             if( msg.message == WM_LBUTTONUP )
3085             {
3086                 ReleaseCapture();
3087                 return 0;
3088             }
3089             if( msg.message == WM_MOUSEMOVE )
3090             {
3091                 POINT tmp;
3092                 tmp.x = LOWORD(msg.lParam);
3093                 tmp.y = HIWORD(msg.lParam);
3094                 if( !PtInRect( &rect, tmp ))
3095                 {
3096                     ReleaseCapture();
3097                     return 1;
3098                 }
3099             }
3100         }
3101         WaitMessage();
3102     }
3103     return 0;
3104 }
3105
3106 /******************************************************************************
3107  *              DragObject (USER.464)
3108  */
3109 DWORD WINAPI DragObject16( HWND16 hwndScope, HWND16 hWnd, UINT16 wObj,
3110                            HANDLE16 hOfStruct, WORD szList, HCURSOR16 hCursor )
3111 {
3112     MSG msg;
3113     LPDRAGINFO16 lpDragInfo;
3114     SEGPTR      spDragInfo;
3115     HCURSOR16   hDragCursor=0, hOldCursor=0, hBummer=0;
3116     HGLOBAL16   hDragInfo  = GlobalAlloc16( GMEM_SHARE | GMEM_ZEROINIT, 2*sizeof(DRAGINFO16));
3117     HCURSOR16   hCurrentCursor = 0;
3118     HWND16      hCurrentWnd = 0;
3119
3120     lpDragInfo = (LPDRAGINFO16) GlobalLock16(hDragInfo);
3121     spDragInfo = K32WOWGlobalLock16(hDragInfo);
3122
3123     if( !lpDragInfo || !spDragInfo ) return 0L;
3124
3125     if (!(hBummer = LoadCursorA(0, MAKEINTRESOURCEA(OCR_NO))))
3126     {
3127         GlobalFree16(hDragInfo);
3128         return 0L;
3129     }
3130
3131     if(hCursor)
3132     {
3133         if( !(hDragCursor = CURSORICON_IconToCursor(hCursor, FALSE)) )
3134         {
3135             GlobalFree16(hDragInfo);
3136             return 0L;
3137         }
3138
3139         if( hDragCursor == hCursor ) hDragCursor = 0;
3140         else hCursor = hDragCursor;
3141
3142         hOldCursor = SetCursor(hDragCursor);
3143     }
3144
3145     lpDragInfo->hWnd   = hWnd;
3146     lpDragInfo->hScope = 0;
3147     lpDragInfo->wFlags = wObj;
3148     lpDragInfo->hList  = szList; /* near pointer! */
3149     lpDragInfo->hOfStruct = hOfStruct;
3150     lpDragInfo->l = 0L;
3151
3152     SetCapture(hWnd);
3153     ShowCursor( TRUE );
3154
3155     do
3156     {
3157         GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST );
3158
3159        *(lpDragInfo+1) = *lpDragInfo;
3160
3161         lpDragInfo->pt.x = msg.pt.x;
3162         lpDragInfo->pt.y = msg.pt.y;
3163
3164         /* update DRAGINFO struct */
3165         TRACE_(msg)("lpDI->hScope = %04x\n",lpDragInfo->hScope);
3166
3167         if( DRAG_QueryUpdate(hwndScope, spDragInfo, FALSE) > 0 )
3168             hCurrentCursor = hCursor;
3169         else
3170         {
3171             hCurrentCursor = hBummer;
3172             lpDragInfo->hScope = 0;
3173         }
3174         if( hCurrentCursor )
3175             SetCursor(hCurrentCursor);
3176
3177         /* send WM_DRAGLOOP */
3178         SendMessage16( hWnd, WM_DRAGLOOP, (WPARAM16)(hCurrentCursor != hBummer),
3179                                           (LPARAM) spDragInfo );
3180         /* send WM_DRAGSELECT or WM_DRAGMOVE */
3181         if( hCurrentWnd != lpDragInfo->hScope )
3182         {
3183             if( hCurrentWnd )
3184                 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 0,
3185                        (LPARAM)MAKELONG(LOWORD(spDragInfo)+sizeof(DRAGINFO16),
3186                                         HIWORD(spDragInfo)) );
3187             hCurrentWnd = lpDragInfo->hScope;
3188             if( hCurrentWnd )
3189                 SendMessage16( hCurrentWnd, WM_DRAGSELECT, 1, (LPARAM)spDragInfo);
3190         }
3191         else
3192             if( hCurrentWnd )
3193                 SendMessage16( hCurrentWnd, WM_DRAGMOVE, 0, (LPARAM)spDragInfo);
3194
3195     } while( msg.message != WM_LBUTTONUP && msg.message != WM_NCLBUTTONUP );
3196
3197     ReleaseCapture();
3198     ShowCursor( FALSE );
3199
3200     if( hCursor )
3201     {
3202         SetCursor( hOldCursor );
3203         if (hDragCursor) DestroyCursor( hDragCursor );
3204     }
3205
3206     if( hCurrentCursor != hBummer )
3207         msg.lParam = SendMessage16( lpDragInfo->hScope, WM_DROPOBJECT,
3208                                    (WPARAM16)hWnd, (LPARAM)spDragInfo );
3209     else
3210         msg.lParam = 0;
3211     GlobalFree16(hDragInfo);
3212
3213     return (DWORD)(msg.lParam);
3214 }
3215
3216
3217 /******************************************************************************
3218  *              GetWindowModuleFileNameA (USER32.@)
3219  */
3220 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3221 {
3222     FIXME("GetWindowModuleFileNameA(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3223           hwnd, lpszFileName, cchFileNameMax);
3224     return 0;
3225 }
3226
3227 /******************************************************************************
3228  *              GetWindowModuleFileNameW (USER32.@)
3229  */
3230 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3231 {
3232     FIXME("GetWindowModuleFileNameW(hwnd 0x%x, lpszFileName %p, cchFileNameMax %u) stub!\n",
3233           hwnd, lpszFileName, cchFileNameMax);
3234     return 0;
3235 }