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