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