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