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