user32: Fix a slightly incorrect assert.
[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             req->ex_style = newval;
1949             break;
1950         case GWLP_ID:
1951             req->flags = SET_WIN_ID;
1952             req->id = newval;
1953             break;
1954         case GWLP_HINSTANCE:
1955             req->flags = SET_WIN_INSTANCE;
1956             req->instance = (void *)newval;
1957             break;
1958         case GWLP_WNDPROC:
1959             req->flags = SET_WIN_UNICODE;
1960             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1961             break;
1962         case GWLP_USERDATA:
1963             req->flags = SET_WIN_USERDATA;
1964             req->user_data = newval;
1965             break;
1966         default:
1967             req->flags = SET_WIN_EXTRA;
1968             req->extra_offset = offset;
1969             req->extra_size = size;
1970             set_win_data( &req->extra_value, newval, size );
1971         }
1972         if ((ok = !wine_server_call_err( req )))
1973         {
1974             switch(offset)
1975             {
1976             case GWL_STYLE:
1977                 wndPtr->dwStyle = newval;
1978                 retval = reply->old_style;
1979                 break;
1980             case GWL_EXSTYLE:
1981                 wndPtr->dwExStyle = newval;
1982                 retval = reply->old_ex_style;
1983                 break;
1984             case GWLP_ID:
1985                 wndPtr->wIDmenu = newval;
1986                 retval = reply->old_id;
1987                 break;
1988             case GWLP_HINSTANCE:
1989                 wndPtr->hInstance = (HINSTANCE)newval;
1990                 retval = (ULONG_PTR)reply->old_instance;
1991                 break;
1992             case GWLP_WNDPROC:
1993                 break;
1994             case GWLP_USERDATA:
1995                 wndPtr->userdata = newval;
1996                 retval = reply->old_user_data;
1997                 break;
1998             default:
1999                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2000                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2001                 break;
2002             }
2003         }
2004     }
2005     SERVER_END_REQ;
2006     WIN_ReleasePtr( wndPtr );
2007
2008     if (!ok) return 0;
2009
2010     if (offset == GWL_STYLE) USER_Driver->pSetWindowStyle( hwnd, retval );
2011
2012     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2013         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2014
2015     return retval;
2016 }
2017
2018
2019 /**********************************************************************
2020  *              GetWindowLong (USER.135)
2021  */
2022 LONG WINAPI GetWindowLong16( HWND16 hwnd, INT16 offset )
2023 {
2024     WND *wndPtr;
2025     LONG_PTR retvalue;
2026     BOOL is_winproc = (offset == GWLP_WNDPROC);
2027
2028     if (offset >= 0)
2029     {
2030         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2031         {
2032             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2033             return 0;
2034         }
2035         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2036         {
2037             if (offset > (int)(wndPtr->cbWndExtra - sizeof(LONG)))
2038             {
2039                 /*
2040                  * Some programs try to access last element from 16 bit
2041                  * code using illegal offset value. Hopefully this is
2042                  * what those programs really expect.
2043                  */
2044                 if (wndPtr->cbWndExtra >= 4 && offset == wndPtr->cbWndExtra - sizeof(WORD))
2045                 {
2046                     INT offset2 = wndPtr->cbWndExtra - sizeof(LONG);
2047                     ERR( "- replaced invalid offset %d with %d\n", offset, offset2 );
2048                     offset = offset2;
2049                 }
2050                 else
2051                 {
2052                     WARN("Invalid offset %d\n", offset );
2053                     WIN_ReleasePtr( wndPtr );
2054                     SetLastError( ERROR_INVALID_INDEX );
2055                     return 0;
2056                 }
2057             }
2058             is_winproc = ((offset == DWLP_DLGPROC) && (wndPtr->flags & WIN_ISDIALOG));
2059             WIN_ReleasePtr( wndPtr );
2060         }
2061     }
2062     retvalue = GetWindowLongA( WIN_Handle32(hwnd), offset );
2063     if (is_winproc) retvalue = (LONG_PTR)WINPROC_GetProc16( (WNDPROC)retvalue, FALSE );
2064     return retvalue;
2065 }
2066
2067
2068 /**********************************************************************
2069  *              GetWindowWord (USER32.@)
2070  */
2071 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2072 {
2073     switch(offset)
2074     {
2075     case GWLP_ID:
2076     case GWLP_HINSTANCE:
2077     case GWLP_HWNDPARENT:
2078         break;
2079     default:
2080         if (offset < 0)
2081         {
2082             WARN("Invalid offset %d\n", offset );
2083             SetLastError( ERROR_INVALID_INDEX );
2084             return 0;
2085         }
2086         break;
2087     }
2088     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2089 }
2090
2091
2092 /**********************************************************************
2093  *              GetWindowLongA (USER32.@)
2094  */
2095 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2096 {
2097     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2098 }
2099
2100
2101 /**********************************************************************
2102  *              GetWindowLongW (USER32.@)
2103  */
2104 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2105 {
2106     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2107 }
2108
2109
2110 /**********************************************************************
2111  *              SetWindowLong (USER.136)
2112  */
2113 LONG WINAPI SetWindowLong16( HWND16 hwnd, INT16 offset, LONG newval )
2114 {
2115     WND *wndPtr;
2116     BOOL is_winproc = (offset == GWLP_WNDPROC);
2117
2118     if (offset == DWLP_DLGPROC)
2119     {
2120         if (!(wndPtr = WIN_GetPtr( WIN_Handle32(hwnd) )))
2121         {
2122             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2123             return 0;
2124         }
2125         if (wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
2126         {
2127             is_winproc = ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2128                           (wndPtr->flags & WIN_ISDIALOG));
2129             WIN_ReleasePtr( wndPtr );
2130         }
2131     }
2132
2133     if (is_winproc)
2134     {
2135         WNDPROC new_proc = WINPROC_AllocProc16( (WNDPROC16)newval );
2136         WNDPROC old_proc = (WNDPROC)SetWindowLongPtrA( WIN_Handle32(hwnd), offset, (LONG_PTR)new_proc );
2137         return (LONG)WINPROC_GetProc16( (WNDPROC)old_proc, FALSE );
2138     }
2139     else return SetWindowLongA( WIN_Handle32(hwnd), offset, newval );
2140 }
2141
2142
2143 /**********************************************************************
2144  *              SetWindowWord (USER32.@)
2145  */
2146 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2147 {
2148     switch(offset)
2149     {
2150     case GWLP_ID:
2151     case GWLP_HINSTANCE:
2152     case GWLP_HWNDPARENT:
2153         break;
2154     default:
2155         if (offset < 0)
2156         {
2157             WARN("Invalid offset %d\n", offset );
2158             SetLastError( ERROR_INVALID_INDEX );
2159             return 0;
2160         }
2161         break;
2162     }
2163     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2164 }
2165
2166
2167 /**********************************************************************
2168  *              SetWindowLongA (USER32.@)
2169  *
2170  * See SetWindowLongW.
2171  */
2172 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2173 {
2174     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2175 }
2176
2177
2178 /**********************************************************************
2179  *              SetWindowLongW (USER32.@) Set window attribute
2180  *
2181  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2182  * value in a window's extra memory.
2183  *
2184  * The _hwnd_ parameter specifies the window.  is the handle to a
2185  * window that has extra memory. The _newval_ parameter contains the
2186  * new attribute or extra memory value.  If positive, the _offset_
2187  * parameter is the byte-addressed location in the window's extra
2188  * memory to set.  If negative, _offset_ specifies the window
2189  * attribute to set, and should be one of the following values:
2190  *
2191  * GWL_EXSTYLE      The window's extended window style
2192  *
2193  * GWL_STYLE        The window's window style.
2194  *
2195  * GWLP_WNDPROC     Pointer to the window's window procedure.
2196  *
2197  * GWLP_HINSTANCE   The window's pplication instance handle.
2198  *
2199  * GWLP_ID          The window's identifier.
2200  *
2201  * GWLP_USERDATA    The window's user-specified data.
2202  *
2203  * If the window is a dialog box, the _offset_ parameter can be one of
2204  * the following values:
2205  *
2206  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2207  *
2208  * DWLP_MSGRESULT   The return value of a message
2209  *                  that the dialog box procedure processed.
2210  *
2211  * DWLP_USER        Application specific information.
2212  *
2213  * RETURNS
2214  *
2215  * If successful, returns the previous value located at _offset_. Otherwise,
2216  * returns 0.
2217  *
2218  * NOTES
2219  *
2220  * Extra memory for a window class is specified by a nonzero cbWndExtra
2221  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2222  * time of class creation.
2223  *
2224  * Using GWL_WNDPROC to set a new window procedure effectively creates
2225  * a window subclass. Use CallWindowProc() in the new windows procedure
2226  * to pass messages to the superclass's window procedure.
2227  *
2228  * The user data is reserved for use by the application which created
2229  * the window.
2230  *
2231  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2232  * instead, call the EnableWindow() function to change the window's
2233  * disabled state.
2234  *
2235  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2236  * SetParent() instead.
2237  *
2238  * Win95:
2239  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2240  * it sends WM_STYLECHANGING before changing the settings
2241  * and WM_STYLECHANGED afterwards.
2242  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2243  */
2244 LONG WINAPI SetWindowLongW(
2245     HWND hwnd,  /* [in] window to alter */
2246     INT offset, /* [in] offset, in bytes, of location to alter */
2247     LONG newval /* [in] new value of location */
2248 ) {
2249     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2250 }
2251
2252
2253 /*******************************************************************
2254  *              GetWindowTextA (USER32.@)
2255  */
2256 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2257 {
2258     WCHAR *buffer;
2259
2260     if (!lpString) return 0;
2261
2262     if (WIN_IsCurrentProcess( hwnd ))
2263         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2264
2265     /* when window belongs to other process, don't send a message */
2266     if (nMaxCount <= 0) return 0;
2267     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2268     get_server_window_text( hwnd, buffer, nMaxCount );
2269     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2270         lpString[nMaxCount-1] = 0;
2271     HeapFree( GetProcessHeap(), 0, buffer );
2272     return strlen(lpString);
2273 }
2274
2275
2276 /*******************************************************************
2277  *              InternalGetWindowText (USER32.@)
2278  */
2279 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2280 {
2281     WND *win;
2282
2283     if (nMaxCount <= 0) return 0;
2284     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2285     if (win == WND_DESKTOP) lpString[0] = 0;
2286     else if (win != WND_OTHER_PROCESS)
2287     {
2288         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2289         else lpString[0] = 0;
2290         WIN_ReleasePtr( win );
2291     }
2292     else
2293     {
2294         get_server_window_text( hwnd, lpString, nMaxCount );
2295     }
2296     return strlenW(lpString);
2297 }
2298
2299
2300 /*******************************************************************
2301  *              GetWindowTextW (USER32.@)
2302  */
2303 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2304 {
2305     if (!lpString) return 0;
2306
2307     if (WIN_IsCurrentProcess( hwnd ))
2308         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2309
2310     /* when window belongs to other process, don't send a message */
2311     if (nMaxCount <= 0) return 0;
2312     get_server_window_text( hwnd, lpString, nMaxCount );
2313     return strlenW(lpString);
2314 }
2315
2316
2317 /*******************************************************************
2318  *              SetWindowTextA (USER32.@)
2319  *              SetWindowText  (USER32.@)
2320  */
2321 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2322 {
2323     if (is_broadcast(hwnd))
2324     {
2325         SetLastError( ERROR_INVALID_PARAMETER );
2326         return FALSE;
2327     }
2328     if (!WIN_IsCurrentProcess( hwnd ))
2329         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2330                debugstr_a(lpString), hwnd );
2331     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2332 }
2333
2334
2335 /*******************************************************************
2336  *              SetWindowTextW (USER32.@)
2337  */
2338 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2339 {
2340     if (is_broadcast(hwnd))
2341     {
2342         SetLastError( ERROR_INVALID_PARAMETER );
2343         return FALSE;
2344     }
2345     if (!WIN_IsCurrentProcess( hwnd ))
2346         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2347                debugstr_w(lpString), hwnd );
2348     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2349 }
2350
2351
2352 /*******************************************************************
2353  *              GetWindowTextLengthA (USER32.@)
2354  */
2355 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2356 {
2357     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2358 }
2359
2360 /*******************************************************************
2361  *              GetWindowTextLengthW (USER32.@)
2362  */
2363 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2364 {
2365     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2366 }
2367
2368
2369 /*******************************************************************
2370  *              IsWindow (USER32.@)
2371  */
2372 BOOL WINAPI IsWindow( HWND hwnd )
2373 {
2374     WND *ptr;
2375     BOOL ret;
2376
2377     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2378     if (ptr == WND_DESKTOP) return TRUE;
2379
2380     if (ptr != WND_OTHER_PROCESS)
2381     {
2382         WIN_ReleasePtr( ptr );
2383         return TRUE;
2384     }
2385
2386     /* check other processes */
2387     SERVER_START_REQ( get_window_info )
2388     {
2389         req->handle = hwnd;
2390         ret = !wine_server_call_err( req );
2391     }
2392     SERVER_END_REQ;
2393     return ret;
2394 }
2395
2396
2397 /***********************************************************************
2398  *              GetWindowThreadProcessId (USER32.@)
2399  */
2400 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2401 {
2402     WND *ptr;
2403     DWORD tid = 0;
2404
2405     if (!(ptr = WIN_GetPtr( hwnd )))
2406     {
2407         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2408         return 0;
2409     }
2410
2411     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2412     {
2413         /* got a valid window */
2414         tid = ptr->tid;
2415         if (process) *process = GetCurrentProcessId();
2416         WIN_ReleasePtr( ptr );
2417         return tid;
2418     }
2419
2420     /* check other processes */
2421     SERVER_START_REQ( get_window_info )
2422     {
2423         req->handle = hwnd;
2424         if (!wine_server_call_err( req ))
2425         {
2426             tid = (DWORD)reply->tid;
2427             if (process) *process = (DWORD)reply->pid;
2428         }
2429     }
2430     SERVER_END_REQ;
2431     return tid;
2432 }
2433
2434
2435 /*****************************************************************
2436  *              GetParent (USER32.@)
2437  */
2438 HWND WINAPI GetParent( HWND hwnd )
2439 {
2440     WND *wndPtr;
2441     HWND retvalue = 0;
2442
2443     if (!(wndPtr = WIN_GetPtr( hwnd )))
2444     {
2445         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2446         return 0;
2447     }
2448     if (wndPtr == WND_DESKTOP) return 0;
2449     if (wndPtr == WND_OTHER_PROCESS)
2450     {
2451         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2452         if (style & (WS_POPUP | WS_CHILD))
2453         {
2454             SERVER_START_REQ( get_window_tree )
2455             {
2456                 req->handle = hwnd;
2457                 if (!wine_server_call_err( req ))
2458                 {
2459                     if (style & WS_POPUP) retvalue = reply->owner;
2460                     else if (style & WS_CHILD) retvalue = reply->parent;
2461                 }
2462             }
2463             SERVER_END_REQ;
2464         }
2465     }
2466     else
2467     {
2468         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2469         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2470         WIN_ReleasePtr( wndPtr );
2471     }
2472     return retvalue;
2473 }
2474
2475
2476 /*****************************************************************
2477  *              GetAncestor (USER32.@)
2478  */
2479 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2480 {
2481     WND *win;
2482     HWND *list, ret = 0;
2483
2484     switch(type)
2485     {
2486     case GA_PARENT:
2487         if (!(win = WIN_GetPtr( hwnd )))
2488         {
2489             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2490             return 0;
2491         }
2492         if (win == WND_DESKTOP) return 0;
2493         if (win != WND_OTHER_PROCESS)
2494         {
2495             ret = win->parent;
2496             WIN_ReleasePtr( win );
2497         }
2498         else /* need to query the server */
2499         {
2500             SERVER_START_REQ( get_window_tree )
2501             {
2502                 req->handle = hwnd;
2503                 if (!wine_server_call_err( req )) ret = reply->parent;
2504             }
2505             SERVER_END_REQ;
2506         }
2507         break;
2508
2509     case GA_ROOT:
2510         if (!(list = list_window_parents( hwnd ))) return 0;
2511
2512         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2513         else
2514         {
2515             int count = 2;
2516             while (list[count]) count++;
2517             ret = list[count - 2];  /* get the one before the desktop */
2518         }
2519         HeapFree( GetProcessHeap(), 0, list );
2520         break;
2521
2522     case GA_ROOTOWNER:
2523         if ((ret = WIN_GetFullHandle( hwnd )) == GetDesktopWindow()) return 0;
2524         for (;;)
2525         {
2526             HWND parent = GetParent( ret );
2527             if (!parent) break;
2528             ret = parent;
2529         }
2530         break;
2531     }
2532     return ret;
2533 }
2534
2535
2536 /*****************************************************************
2537  *              SetParent (USER32.@)
2538  */
2539 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2540 {
2541     HWND full_handle;
2542     HWND old_parent = 0;
2543     BOOL was_visible;
2544     WND *wndPtr;
2545     BOOL ret;
2546
2547     if (is_broadcast(hwnd) || is_broadcast(parent))
2548     {
2549         SetLastError(ERROR_INVALID_PARAMETER);
2550         return 0;
2551     }
2552
2553     if (!parent) parent = GetDesktopWindow();
2554     else parent = WIN_GetFullHandle( parent );
2555
2556     if (!IsWindow( parent ))
2557     {
2558         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2559         return 0;
2560     }
2561
2562     /* Some applications try to set a child as a parent */
2563     if (IsChild(hwnd, parent))
2564     {
2565         SetLastError( ERROR_INVALID_PARAMETER );
2566         return 0;
2567     }
2568
2569     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2570         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2571
2572     /* Windows hides the window first, then shows it again
2573      * including the WM_SHOWWINDOW messages and all */
2574     was_visible = ShowWindow( hwnd, SW_HIDE );
2575
2576     wndPtr = WIN_GetPtr( hwnd );
2577     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2578
2579     SERVER_START_REQ( set_parent )
2580     {
2581         req->handle = hwnd;
2582         req->parent = parent;
2583         if ((ret = !wine_server_call( req )))
2584         {
2585             old_parent = reply->old_parent;
2586             wndPtr->parent = parent = reply->full_parent;
2587         }
2588
2589     }
2590     SERVER_END_REQ;
2591     WIN_ReleasePtr( wndPtr );
2592     if (!ret) return 0;
2593
2594     USER_Driver->pSetParent( full_handle, parent, old_parent );
2595
2596     /* SetParent additionally needs to make hwnd the topmost window
2597        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2598        WM_WINDOWPOSCHANGED notification messages.
2599     */
2600     SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0,
2601                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2602     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2603      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2604
2605     return old_parent;
2606 }
2607
2608
2609 /*******************************************************************
2610  *              IsChild (USER32.@)
2611  */
2612 BOOL WINAPI IsChild( HWND parent, HWND child )
2613 {
2614     HWND *list = list_window_parents( child );
2615     int i;
2616     BOOL ret;
2617
2618     if (!list) return FALSE;
2619     parent = WIN_GetFullHandle( parent );
2620     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2621     ret = list[i] && list[i+1];
2622     HeapFree( GetProcessHeap(), 0, list );
2623     return ret;
2624 }
2625
2626
2627 /***********************************************************************
2628  *              IsWindowVisible (USER32.@)
2629  */
2630 BOOL WINAPI IsWindowVisible( HWND hwnd )
2631 {
2632     HWND *list;
2633     BOOL retval = TRUE;
2634     int i;
2635
2636     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2637     if (!(list = list_window_parents( hwnd ))) return TRUE;
2638     if (list[0] && list[1])  /* desktop window is considered always visible so we don't check it */
2639     {
2640         for (i = 0; list[i+1]; i++)
2641             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2642         retval = !list[i+1];
2643     }
2644     HeapFree( GetProcessHeap(), 0, list );
2645     return retval;
2646 }
2647
2648
2649 /***********************************************************************
2650  *           WIN_IsWindowDrawable
2651  *
2652  * hwnd is drawable when it is visible, all parents are not
2653  * minimized, and it is itself not minimized unless we are
2654  * trying to draw its default class icon.
2655  */
2656 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2657 {
2658     HWND *list;
2659     BOOL retval = TRUE;
2660     int i;
2661     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2662
2663     if (!(style & WS_VISIBLE)) return FALSE;
2664     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2665
2666     if (!(list = list_window_parents( hwnd ))) return TRUE;
2667     if (list[0] && list[1])  /* desktop window is considered always visible so we don't check it */
2668     {
2669         for (i = 0; list[i+1]; i++)
2670             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2671                 break;
2672         retval = !list[i+1];
2673     }
2674     HeapFree( GetProcessHeap(), 0, list );
2675     return retval;
2676 }
2677
2678
2679 /*******************************************************************
2680  *              GetTopWindow (USER32.@)
2681  */
2682 HWND WINAPI GetTopWindow( HWND hwnd )
2683 {
2684     if (!hwnd) hwnd = GetDesktopWindow();
2685     return GetWindow( hwnd, GW_CHILD );
2686 }
2687
2688
2689 /*******************************************************************
2690  *              GetWindow (USER32.@)
2691  */
2692 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2693 {
2694     HWND retval = 0;
2695
2696     if (rel == GW_OWNER)  /* this one may be available locally */
2697     {
2698         WND *wndPtr = WIN_GetPtr( hwnd );
2699         if (!wndPtr)
2700         {
2701             SetLastError( ERROR_INVALID_HANDLE );
2702             return 0;
2703         }
2704         if (wndPtr == WND_DESKTOP) return 0;
2705         if (wndPtr != WND_OTHER_PROCESS)
2706         {
2707             retval = wndPtr->owner;
2708             WIN_ReleasePtr( wndPtr );
2709             return retval;
2710         }
2711         /* else fall through to server call */
2712     }
2713
2714     SERVER_START_REQ( get_window_tree )
2715     {
2716         req->handle = hwnd;
2717         if (!wine_server_call_err( req ))
2718         {
2719             switch(rel)
2720             {
2721             case GW_HWNDFIRST:
2722                 retval = reply->first_sibling;
2723                 break;
2724             case GW_HWNDLAST:
2725                 retval = reply->last_sibling;
2726                 break;
2727             case GW_HWNDNEXT:
2728                 retval = reply->next_sibling;
2729                 break;
2730             case GW_HWNDPREV:
2731                 retval = reply->prev_sibling;
2732                 break;
2733             case GW_OWNER:
2734                 retval = reply->owner;
2735                 break;
2736             case GW_CHILD:
2737                 retval = reply->first_child;
2738                 break;
2739             }
2740         }
2741     }
2742     SERVER_END_REQ;
2743     return retval;
2744 }
2745
2746
2747 /*******************************************************************
2748  *              ShowOwnedPopups (USER32.@)
2749  */
2750 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2751 {
2752     int count = 0;
2753     WND *pWnd;
2754     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
2755
2756     if (!win_array) return TRUE;
2757
2758     while (win_array[count]) count++;
2759     while (--count >= 0)
2760     {
2761         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
2762         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
2763         if (pWnd == WND_OTHER_PROCESS) continue;
2764         if (fShow)
2765         {
2766             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
2767             {
2768                 WIN_ReleasePtr( pWnd );
2769                 /* In Windows, ShowOwnedPopups(TRUE) generates
2770                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
2771                  * regardless of the state of the owner
2772                  */
2773                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
2774                 continue;
2775             }
2776         }
2777         else
2778         {
2779             if (pWnd->dwStyle & WS_VISIBLE)
2780             {
2781                 WIN_ReleasePtr( pWnd );
2782                 /* In Windows, ShowOwnedPopups(FALSE) generates
2783                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
2784                  * regardless of the state of the owner
2785                  */
2786                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
2787                 continue;
2788             }
2789         }
2790         WIN_ReleasePtr( pWnd );
2791     }
2792     HeapFree( GetProcessHeap(), 0, win_array );
2793     return TRUE;
2794 }
2795
2796
2797 /*******************************************************************
2798  *              GetLastActivePopup (USER32.@)
2799  */
2800 HWND WINAPI GetLastActivePopup( HWND hwnd )
2801 {
2802     HWND retval = hwnd;
2803
2804     SERVER_START_REQ( get_window_info )
2805     {
2806         req->handle = hwnd;
2807         if (!wine_server_call_err( req )) retval = reply->last_active;
2808     }
2809     SERVER_END_REQ;
2810     return retval;
2811 }
2812
2813
2814 /*******************************************************************
2815  *           WIN_ListChildren
2816  *
2817  * Build an array of the children of a given window. The array must be
2818  * freed with HeapFree. Returns NULL when no windows are found.
2819  */
2820 HWND *WIN_ListChildren( HWND hwnd )
2821 {
2822     return list_window_children( hwnd, 0, 0 );
2823 }
2824
2825
2826 /*******************************************************************
2827  *              EnumWindows (USER32.@)
2828  */
2829 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
2830 {
2831     HWND *list;
2832     BOOL ret = TRUE;
2833     int i;
2834
2835     USER_CheckNotLock();
2836
2837     /* We have to build a list of all windows first, to avoid */
2838     /* unpleasant side-effects, for instance if the callback */
2839     /* function changes the Z-order of the windows.          */
2840
2841     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
2842
2843     /* Now call the callback function for every window */
2844
2845     for (i = 0; list[i]; i++)
2846     {
2847         /* Make sure that the window still exists */
2848         if (!IsWindow( list[i] )) continue;
2849         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
2850     }
2851     HeapFree( GetProcessHeap(), 0, list );
2852     return ret;
2853 }
2854
2855
2856 /**********************************************************************
2857  *              EnumThreadWindows (USER32.@)
2858  */
2859 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
2860 {
2861     HWND *list;
2862     int i;
2863
2864     USER_CheckNotLock();
2865
2866     if (!(list = list_window_children( GetDesktopWindow(), 0, id ))) return TRUE;
2867
2868     /* Now call the callback function for every window */
2869
2870     for (i = 0; list[i]; i++)
2871         if (!func( list[i], lParam )) break;
2872     HeapFree( GetProcessHeap(), 0, list );
2873     return TRUE;
2874 }
2875
2876
2877 /**********************************************************************
2878  *           WIN_EnumChildWindows
2879  *
2880  * Helper function for EnumChildWindows().
2881  */
2882 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
2883 {
2884     HWND *childList;
2885     BOOL ret = FALSE;
2886
2887     for ( ; *list; list++)
2888     {
2889         /* Make sure that the window still exists */
2890         if (!IsWindow( *list )) continue;
2891         /* Build children list first */
2892         childList = WIN_ListChildren( *list );
2893
2894         ret = func( *list, lParam );
2895
2896         if (childList)
2897         {
2898             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
2899             HeapFree( GetProcessHeap(), 0, childList );
2900         }
2901         if (!ret) return FALSE;
2902     }
2903     return TRUE;
2904 }
2905
2906
2907 /**********************************************************************
2908  *              EnumChildWindows (USER32.@)
2909  */
2910 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
2911 {
2912     HWND *list;
2913     BOOL ret;
2914
2915     USER_CheckNotLock();
2916
2917     if (!(list = WIN_ListChildren( parent ))) return FALSE;
2918     ret = WIN_EnumChildWindows( list, func, lParam );
2919     HeapFree( GetProcessHeap(), 0, list );
2920     return ret;
2921 }
2922
2923
2924 /*******************************************************************
2925  *              AnyPopup (USER.52)
2926  */
2927 BOOL16 WINAPI AnyPopup16(void)
2928 {
2929     return AnyPopup();
2930 }
2931
2932
2933 /*******************************************************************
2934  *              AnyPopup (USER32.@)
2935  */
2936 BOOL WINAPI AnyPopup(void)
2937 {
2938     int i;
2939     BOOL retvalue;
2940     HWND *list = WIN_ListChildren( GetDesktopWindow() );
2941
2942     if (!list) return FALSE;
2943     for (i = 0; list[i]; i++)
2944     {
2945         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
2946     }
2947     retvalue = (list[i] != 0);
2948     HeapFree( GetProcessHeap(), 0, list );
2949     return retvalue;
2950 }
2951
2952
2953 /*******************************************************************
2954  *              FlashWindow (USER32.@)
2955  */
2956 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
2957 {
2958     WND *wndPtr;
2959
2960     TRACE("%p\n", hWnd);
2961
2962     if (IsIconic( hWnd ))
2963     {
2964         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
2965
2966         wndPtr = WIN_GetPtr(hWnd);
2967         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2968         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
2969         {
2970             wndPtr->flags |= WIN_NCACTIVATED;
2971         }
2972         else
2973         {
2974             wndPtr->flags &= ~WIN_NCACTIVATED;
2975         }
2976         WIN_ReleasePtr( wndPtr );
2977         return TRUE;
2978     }
2979     else
2980     {
2981         WPARAM wparam;
2982
2983         wndPtr = WIN_GetPtr(hWnd);
2984         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
2985         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
2986
2987         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
2988         else wparam = (hWnd == GetForegroundWindow());
2989
2990         WIN_ReleasePtr( wndPtr );
2991         SendMessageW( hWnd, WM_NCACTIVATE, wparam, (LPARAM)0 );
2992         return wparam;
2993     }
2994 }
2995
2996 /*******************************************************************
2997  *              FlashWindowEx (USER32.@)
2998  */
2999 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3000 {
3001     FIXME("%p\n", pfwi);
3002     return TRUE;
3003 }
3004
3005 /*******************************************************************
3006  *              GetWindowContextHelpId (USER32.@)
3007  */
3008 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3009 {
3010     DWORD retval;
3011     WND *wnd = WIN_GetPtr( hwnd );
3012     if (!wnd || wnd == WND_DESKTOP) return 0;
3013     if (wnd == WND_OTHER_PROCESS)
3014     {
3015         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3016         return 0;
3017     }
3018     retval = wnd->helpContext;
3019     WIN_ReleasePtr( wnd );
3020     return retval;
3021 }
3022
3023
3024 /*******************************************************************
3025  *              SetWindowContextHelpId (USER32.@)
3026  */
3027 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3028 {
3029     WND *wnd = WIN_GetPtr( hwnd );
3030     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3031     if (wnd == WND_OTHER_PROCESS)
3032     {
3033         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3034         return 0;
3035     }
3036     wnd->helpContext = id;
3037     WIN_ReleasePtr( wnd );
3038     return TRUE;
3039 }
3040
3041
3042 /*******************************************************************
3043  *              DragDetect (USER32.@)
3044  */
3045 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3046 {
3047     MSG msg;
3048     RECT rect;
3049     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3050     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3051
3052     rect.left = pt.x - wDragWidth;
3053     rect.right = pt.x + wDragWidth;
3054
3055     rect.top = pt.y - wDragHeight;
3056     rect.bottom = pt.y + wDragHeight;
3057
3058     SetCapture(hWnd);
3059
3060     while(1)
3061     {
3062         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3063         {
3064             if( msg.message == WM_LBUTTONUP )
3065             {
3066                 ReleaseCapture();
3067                 return 0;
3068             }
3069             if( msg.message == WM_MOUSEMOVE )
3070             {
3071                 POINT tmp;
3072                 tmp.x = (short)LOWORD(msg.lParam);
3073                 tmp.y = (short)HIWORD(msg.lParam);
3074                 if( !PtInRect( &rect, tmp ))
3075                 {
3076                     ReleaseCapture();
3077                     return 1;
3078                 }
3079             }
3080         }
3081         WaitMessage();
3082     }
3083     return 0;
3084 }
3085
3086 /******************************************************************************
3087  *              GetWindowModuleFileNameA (USER32.@)
3088  */
3089 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR lpszFileName, UINT cchFileNameMax)
3090 {
3091     FIXME("GetWindowModuleFileNameA(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3092           hwnd, lpszFileName, cchFileNameMax);
3093     return 0;
3094 }
3095
3096 /******************************************************************************
3097  *              GetWindowModuleFileNameW (USER32.@)
3098  */
3099 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR lpszFileName, UINT cchFileNameMax)
3100 {
3101     FIXME("GetWindowModuleFileNameW(hwnd %p, lpszFileName %p, cchFileNameMax %u) stub!\n",
3102           hwnd, lpszFileName, cchFileNameMax);
3103     return 0;
3104 }
3105
3106 /******************************************************************************
3107  *              GetWindowInfo (USER32.@)
3108  *
3109  * Note: tests show that Windows doesn't check cbSize of the structure.
3110  */
3111 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3112 {
3113     if (!pwi) return FALSE;
3114     if (!IsWindow(hwnd)) return FALSE;
3115
3116     GetWindowRect(hwnd, &pwi->rcWindow);
3117     GetClientRect(hwnd, &pwi->rcClient);
3118     /* translate to screen coordinates */
3119     MapWindowPoints(hwnd, 0, (LPPOINT)&pwi->rcClient, 2);
3120
3121     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3122     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3123     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3124
3125     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3126     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3127
3128     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3129     pwi->wCreatorVersion = 0x0400;
3130
3131     return TRUE;
3132 }
3133
3134 /******************************************************************************
3135  *              SwitchDesktop (USER32.@)
3136  *
3137  * NOTES: Sets the current input or interactive desktop.
3138  */
3139 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3140 {
3141     FIXME("SwitchDesktop(hwnd %p) stub!\n", hDesktop);
3142     return TRUE;
3143 }
3144
3145 /*****************************************************************************
3146  *              SetLayeredWindowAttributes (USER32.@)
3147  */
3148 BOOL WINAPI SetLayeredWindowAttributes( HWND hWnd, COLORREF rgbKey, 
3149                                         BYTE bAlpha, DWORD dwFlags )
3150 {
3151     FIXME("(%p,0x%.8x,%d,%d): stub!\n", hWnd, rgbKey, bAlpha, dwFlags);
3152     return TRUE;
3153 }
3154
3155 /*****************************************************************************
3156  *              UpdateLayeredWindow (USER32.@)
3157  */
3158 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3159                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3160                                  DWORD dwFlags)
3161 {
3162     static int once;
3163     if (!once)
3164     {
3165         once = 1;
3166         FIXME("(%p,%p,%p,%p,%p,%p,0x%08x,%p,%d): stub!\n",
3167               hwnd, hdcDst, pptDst, psize, hdcSrc, pptSrc, crKey, pblend, dwFlags);
3168     }
3169     return 0;
3170 }
3171
3172 /* 64bit versions */
3173
3174 #ifdef GetWindowLongPtrW
3175 #undef GetWindowLongPtrW
3176 #endif
3177
3178 #ifdef GetWindowLongPtrA
3179 #undef GetWindowLongPtrA
3180 #endif
3181
3182 #ifdef SetWindowLongPtrW
3183 #undef SetWindowLongPtrW
3184 #endif
3185
3186 #ifdef SetWindowLongPtrA
3187 #undef SetWindowLongPtrA
3188 #endif
3189
3190 /*****************************************************************************
3191  *              GetWindowLongPtrW (USER32.@)
3192  */
3193 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3194 {
3195     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3196 }
3197
3198 /*****************************************************************************
3199  *              GetWindowLongPtrA (USER32.@)
3200  */
3201 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3202 {
3203     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3204 }
3205
3206 /*****************************************************************************
3207  *              SetWindowLongPtrW (USER32.@)
3208  */
3209 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3210 {
3211     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3212 }
3213
3214 /*****************************************************************************
3215  *              SetWindowLongPtrA (USER32.@)
3216  */
3217 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3218 {
3219     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3220 }