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