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