comdlg32/tests: Don't test function directly when reporting GetLastError().
[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     (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(" %08lx", 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     (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(" %08lx", 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     /*
1328      * WS_EX_WINDOWEDGE appears to be enforced based on the other styles, so
1329      * why does the user get to set it?
1330      */
1331
1332     if ((wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) ||
1333           (wndPtr->dwStyle & (WS_DLGFRAME | WS_THICKFRAME)))
1334         wndPtr->dwExStyle |= WS_EX_WINDOWEDGE;
1335     else
1336         wndPtr->dwExStyle &= ~WS_EX_WINDOWEDGE;
1337
1338     if (!(wndPtr->dwStyle & (WS_CHILD | WS_POPUP)))
1339         wndPtr->flags |= WIN_NEED_SIZE;
1340
1341     SERVER_START_REQ( set_window_info )
1342     {
1343         req->handle    = wine_server_user_handle( hwnd );
1344         req->flags     = SET_WIN_STYLE | SET_WIN_EXSTYLE | SET_WIN_INSTANCE | SET_WIN_UNICODE;
1345         req->style     = wndPtr->dwStyle;
1346         req->ex_style  = wndPtr->dwExStyle;
1347         req->instance  = wine_server_client_ptr( wndPtr->hInstance );
1348         req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
1349         req->extra_offset = -1;
1350         wine_server_call( req );
1351     }
1352     SERVER_END_REQ;
1353
1354     /* Set the window menu */
1355
1356     if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD)
1357     {
1358         if (cs->hMenu)
1359         {
1360             if (!MENU_SetMenu(hwnd, cs->hMenu))
1361             {
1362                 WIN_ReleasePtr( wndPtr );
1363                 free_window_handle( hwnd );
1364                 return 0;
1365             }
1366         }
1367         else
1368         {
1369             LPCWSTR menuName = (LPCWSTR)GetClassLongPtrW( hwnd, GCLP_MENUNAME );
1370             if (menuName)
1371             {
1372                 cs->hMenu = LoadMenuW( cs->hInstance, menuName );
1373                 if (cs->hMenu) MENU_SetMenu( hwnd, cs->hMenu );
1374             }
1375         }
1376     }
1377     else SetWindowLongPtrW( hwnd, GWLP_ID, (ULONG_PTR)cs->hMenu );
1378
1379     /* call the WH_CBT hook */
1380
1381     /* the window style passed to the hook must be the real window style,
1382      * rather than just the window style that the caller to CreateWindowEx
1383      * passed in, so we have to copy the original CREATESTRUCT and get the
1384      * the real style. */
1385     cbcs = *cs;
1386     cbcs.style = wndPtr->dwStyle;
1387     cbtc.lpcs = &cbcs;
1388     cbtc.hwndInsertAfter = HWND_TOP;
1389     WIN_ReleasePtr( wndPtr );
1390     if (HOOK_CallHooks( WH_CBT, HCBT_CREATEWND, (WPARAM)hwnd, (LPARAM)&cbtc, unicode )) goto failed;
1391
1392     /* send the WM_GETMINMAXINFO message and fix the size if needed */
1393
1394     cx = cs->cx;
1395     cy = cs->cy;
1396     if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD)))
1397     {
1398         POINT maxSize, maxPos, minTrack, maxTrack;
1399         WINPOS_GetMinMaxInfo( hwnd, &maxSize, &maxPos, &minTrack, &maxTrack);
1400         if (maxTrack.x < cx) cx = maxTrack.x;
1401         if (maxTrack.y < cy) cy = maxTrack.y;
1402         if (minTrack.x > cx) cx = minTrack.x;
1403         if (minTrack.y > cy) cy = minTrack.y;
1404     }
1405
1406     if (cx < 0) cx = 0;
1407     if (cy < 0) cy = 0;
1408     SetRect( &rect, cs->x, cs->y, cs->x + cx, cs->y + cy );
1409     /* check for wraparound */
1410     if (cs->x + cx < cs->x) rect.right = 0x7fffffff;
1411     if (cs->y + cy < cs->y) rect.bottom = 0x7fffffff;
1412     if (!set_window_pos( hwnd, 0, SWP_NOZORDER | SWP_NOACTIVATE, &rect, &rect, NULL )) goto failed;
1413
1414     /* send WM_NCCREATE */
1415
1416     TRACE( "hwnd %p cs %d,%d %dx%d\n", hwnd, cs->x, cs->y, cx, cy );
1417     if (unicode)
1418         result = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1419     else
1420         result = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
1421     if (!result)
1422     {
1423         WARN( "%p: aborted by WM_NCCREATE\n", hwnd );
1424         goto failed;
1425     }
1426
1427     /* send WM_NCCALCSIZE */
1428
1429     if (WIN_GetRectangles( hwnd, COORDS_PARENT, &rect, NULL ))
1430     {
1431         /* yes, even if the CBT hook was called with HWND_TOP */
1432         HWND insert_after = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) ? HWND_BOTTOM : HWND_TOP;
1433         RECT client_rect = rect;
1434
1435         /* the rectangle is in screen coords for WM_NCCALCSIZE when wparam is FALSE */
1436         MapWindowPoints( parent, 0, (POINT *)&client_rect, 2 );
1437         SendMessageW( hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&client_rect );
1438         MapWindowPoints( 0, parent, (POINT *)&client_rect, 2 );
1439         set_window_pos( hwnd, insert_after, SWP_NOACTIVATE, &rect, &client_rect, NULL );
1440     }
1441     else return 0;
1442
1443     /* send WM_CREATE */
1444
1445     if (unicode)
1446         result = SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs );
1447     else
1448         result = SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs );
1449     if (result == -1) goto failed;
1450
1451     /* call the driver */
1452
1453     if (!USER_Driver->pCreateWindow( hwnd )) goto failed;
1454
1455     NotifyWinEvent(EVENT_OBJECT_CREATE, hwnd, OBJID_WINDOW, 0);
1456
1457     /* send the size messages */
1458
1459     if (!(wndPtr = WIN_GetPtr( hwnd )) ||
1460           wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
1461     if (!(wndPtr->flags & WIN_NEED_SIZE))
1462     {
1463         WIN_ReleasePtr( wndPtr );
1464         WIN_GetRectangles( hwnd, COORDS_PARENT, NULL, &rect );
1465         SendMessageW( hwnd, WM_SIZE, SIZE_RESTORED,
1466                       MAKELONG(rect.right-rect.left, rect.bottom-rect.top));
1467         SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( rect.left, rect.top ) );
1468     }
1469     else WIN_ReleasePtr( wndPtr );
1470
1471     /* Show the window, maximizing or minimizing if needed */
1472
1473     style = WIN_SetStyle( hwnd, 0, WS_MAXIMIZE | WS_MINIMIZE );
1474     if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1475     {
1476         RECT newPos;
1477         UINT swFlag = (style & WS_MINIMIZE) ? SW_MINIMIZE : SW_MAXIMIZE;
1478
1479         swFlag = WINPOS_MinMaximize( hwnd, swFlag, &newPos );
1480         swFlag |= SWP_FRAMECHANGED; /* Frame always gets changed */
1481         if (!(style & WS_VISIBLE) || (style & WS_CHILD) || GetActiveWindow()) swFlag |= SWP_NOACTIVATE;
1482         SetWindowPos( hwnd, 0, newPos.left, newPos.top, newPos.right - newPos.left,
1483                       newPos.bottom - newPos.top, swFlag );
1484     }
1485
1486     /* Notify the parent window only */
1487
1488     send_parent_notify( hwnd, WM_CREATE );
1489     if (!IsWindow( hwnd )) return 0;
1490
1491     if (cs->style & WS_VISIBLE)
1492     {
1493         if (cs->style & WS_MAXIMIZE)
1494             sw = SW_SHOW;
1495         else if (cs->style & WS_MINIMIZE)
1496             sw = SW_SHOWMINIMIZED;
1497
1498         ShowWindow( hwnd, sw );
1499         if (cs->dwExStyle & WS_EX_MDICHILD)
1500         {
1501             SendMessageW(cs->hwndParent, WM_MDIREFRESHMENU, 0, 0);
1502             /* ShowWindow won't activate child windows */
1503             SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE );
1504         }
1505     }
1506
1507     /* Call WH_SHELL hook */
1508
1509     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) && !GetWindow( hwnd, GW_OWNER ))
1510         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWCREATED, (WPARAM)hwnd, 0, TRUE );
1511
1512     TRACE("created window %p\n", hwnd);
1513     return hwnd;
1514
1515 failed:
1516     WIN_DestroyWindow( hwnd );
1517     return 0;
1518 }
1519
1520
1521 /***********************************************************************
1522  *              CreateWindowExA (USER32.@)
1523  */
1524 HWND WINAPI CreateWindowExA( DWORD exStyle, LPCSTR className,
1525                                  LPCSTR windowName, DWORD style, INT x,
1526                                  INT y, INT width, INT height,
1527                                  HWND parent, HMENU menu,
1528                                  HINSTANCE instance, LPVOID data )
1529 {
1530     CREATESTRUCTA cs;
1531
1532     cs.lpCreateParams = data;
1533     cs.hInstance      = instance;
1534     cs.hMenu          = menu;
1535     cs.hwndParent     = parent;
1536     cs.x              = x;
1537     cs.y              = y;
1538     cs.cx             = width;
1539     cs.cy             = height;
1540     cs.style          = style;
1541     cs.lpszName       = windowName;
1542     cs.lpszClass      = className;
1543     cs.dwExStyle      = exStyle;
1544
1545     if (!IS_INTRESOURCE(className))
1546     {
1547         WCHAR bufferW[256];
1548         if (!MultiByteToWideChar( CP_ACP, 0, className, -1, bufferW, sizeof(bufferW)/sizeof(WCHAR) ))
1549             return 0;
1550         return wow_handlers.create_window( (CREATESTRUCTW *)&cs, bufferW, instance, FALSE );
1551     }
1552     /* Note: we rely on the fact that CREATESTRUCTA and */
1553     /* CREATESTRUCTW have the same layout. */
1554     return wow_handlers.create_window( (CREATESTRUCTW *)&cs, (LPCWSTR)className, instance, FALSE );
1555 }
1556
1557
1558 /***********************************************************************
1559  *              CreateWindowExW (USER32.@)
1560  */
1561 HWND WINAPI CreateWindowExW( DWORD exStyle, LPCWSTR className,
1562                                  LPCWSTR windowName, DWORD style, INT x,
1563                                  INT y, INT width, INT height,
1564                                  HWND parent, HMENU menu,
1565                                  HINSTANCE instance, LPVOID data )
1566 {
1567     CREATESTRUCTW cs;
1568
1569     cs.lpCreateParams = data;
1570     cs.hInstance      = instance;
1571     cs.hMenu          = menu;
1572     cs.hwndParent     = parent;
1573     cs.x              = x;
1574     cs.y              = y;
1575     cs.cx             = width;
1576     cs.cy             = height;
1577     cs.style          = style;
1578     cs.lpszName       = windowName;
1579     cs.lpszClass      = className;
1580     cs.dwExStyle      = exStyle;
1581
1582     return wow_handlers.create_window( &cs, className, instance, TRUE );
1583 }
1584
1585
1586 /***********************************************************************
1587  *           WIN_SendDestroyMsg
1588  */
1589 static void WIN_SendDestroyMsg( HWND hwnd )
1590 {
1591     GUITHREADINFO info;
1592
1593     info.cbSize = sizeof(info);
1594     if (GetGUIThreadInfo( GetCurrentThreadId(), &info ))
1595     {
1596         if (hwnd == info.hwndCaret) DestroyCaret();
1597         if (hwnd == info.hwndActive) WINPOS_ActivateOtherWindow( hwnd );
1598     }
1599
1600     /*
1601      * Send the WM_DESTROY to the window.
1602      */
1603     SendMessageW( hwnd, WM_DESTROY, 0, 0);
1604
1605     /*
1606      * This WM_DESTROY message can trigger re-entrant calls to DestroyWindow
1607      * make sure that the window still exists when we come back.
1608      */
1609     if (IsWindow(hwnd))
1610     {
1611         HWND* pWndArray;
1612         int i;
1613
1614         if (!(pWndArray = WIN_ListChildren( hwnd ))) return;
1615
1616         for (i = 0; pWndArray[i]; i++)
1617         {
1618             if (IsWindow( pWndArray[i] )) WIN_SendDestroyMsg( pWndArray[i] );
1619         }
1620         HeapFree( GetProcessHeap(), 0, pWndArray );
1621     }
1622     else
1623       WARN("\tdestroyed itself while in WM_DESTROY!\n");
1624 }
1625
1626
1627 /***********************************************************************
1628  *              DestroyWindow (USER32.@)
1629  */
1630 BOOL WINAPI DestroyWindow( HWND hwnd )
1631 {
1632     BOOL is_child;
1633
1634     if (!(hwnd = WIN_IsCurrentThread( hwnd )) || is_desktop_window( hwnd ))
1635     {
1636         SetLastError( ERROR_ACCESS_DENIED );
1637         return FALSE;
1638     }
1639
1640     TRACE("(%p)\n", hwnd);
1641
1642       /* Call hooks */
1643
1644     if (HOOK_CallHooks( WH_CBT, HCBT_DESTROYWND, (WPARAM)hwnd, 0, TRUE )) return FALSE;
1645
1646     if (MENU_IsMenuActive() == hwnd)
1647         EndMenu();
1648
1649     is_child = (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) != 0;
1650
1651     if (is_child)
1652     {
1653         if (!USER_IsExitingThread( GetCurrentThreadId() ))
1654             send_parent_notify( hwnd, WM_DESTROY );
1655     }
1656     else if (!GetWindow( hwnd, GW_OWNER ))
1657     {
1658         HOOK_CallHooks( WH_SHELL, HSHELL_WINDOWDESTROYED, (WPARAM)hwnd, 0L, TRUE );
1659         /* FIXME: clean up palette - see "Internals" p.352 */
1660     }
1661
1662     if (!IsWindow(hwnd)) return TRUE;
1663
1664       /* Hide the window */
1665     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)
1666     {
1667         /* Only child windows receive WM_SHOWWINDOW in DestroyWindow() */
1668         if (is_child)
1669             ShowWindow( hwnd, SW_HIDE );
1670         else
1671             SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE |
1672                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_HIDEWINDOW );
1673     }
1674
1675     if (!IsWindow(hwnd)) return TRUE;
1676
1677       /* Recursively destroy owned windows */
1678
1679     if (!is_child)
1680     {
1681         for (;;)
1682         {
1683             int i, got_one = 0;
1684             HWND *list = WIN_ListChildren( GetDesktopWindow() );
1685             if (list)
1686             {
1687                 for (i = 0; list[i]; i++)
1688                 {
1689                     if (GetWindow( list[i], GW_OWNER ) != hwnd) continue;
1690                     if (WIN_IsCurrentThread( list[i] ))
1691                     {
1692                         DestroyWindow( list[i] );
1693                         got_one = 1;
1694                         continue;
1695                     }
1696                     WIN_SetOwner( list[i], 0 );
1697                 }
1698                 HeapFree( GetProcessHeap(), 0, list );
1699             }
1700             if (!got_one) break;
1701         }
1702     }
1703
1704       /* Send destroy messages */
1705
1706     WIN_SendDestroyMsg( hwnd );
1707     if (!IsWindow( hwnd )) return TRUE;
1708
1709     if (GetClipboardOwner() == hwnd)
1710         CLIPBOARD_ReleaseOwner();
1711
1712       /* Destroy the window storage */
1713
1714     WIN_DestroyWindow( hwnd );
1715     return TRUE;
1716 }
1717
1718
1719 /***********************************************************************
1720  *              CloseWindow (USER32.@)
1721  */
1722 BOOL WINAPI CloseWindow( HWND hwnd )
1723 {
1724     if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_CHILD) return FALSE;
1725     ShowWindow( hwnd, SW_MINIMIZE );
1726     return TRUE;
1727 }
1728
1729
1730 /***********************************************************************
1731  *              OpenIcon (USER32.@)
1732  */
1733 BOOL WINAPI OpenIcon( HWND hwnd )
1734 {
1735     if (!IsIconic( hwnd )) return FALSE;
1736     ShowWindow( hwnd, SW_SHOWNORMAL );
1737     return TRUE;
1738 }
1739
1740
1741 /***********************************************************************
1742  *              FindWindowExW (USER32.@)
1743  */
1744 HWND WINAPI FindWindowExW( HWND parent, HWND child, LPCWSTR className, LPCWSTR title )
1745 {
1746     HWND *list = NULL;
1747     HWND retvalue = 0;
1748     int i = 0, len = 0;
1749     WCHAR *buffer = NULL;
1750
1751     if (!parent && child) parent = GetDesktopWindow();
1752     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
1753
1754     if (title)
1755     {
1756         len = strlenW(title) + 1;  /* one extra char to check for chars beyond the end */
1757         if (!(buffer = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ))) return 0;
1758     }
1759
1760     if (!(list = list_window_children( 0, parent, className, 0 ))) goto done;
1761
1762     if (child)
1763     {
1764         child = WIN_GetFullHandle( child );
1765         while (list[i] && list[i] != child) i++;
1766         if (!list[i]) goto done;
1767         i++;  /* start from next window */
1768     }
1769
1770     if (title)
1771     {
1772         while (list[i])
1773         {
1774             if (GetWindowTextW( list[i], buffer, len + 1 ))
1775             {
1776                 if (!strcmpiW( buffer, title )) break;
1777             }
1778             else
1779             {
1780                 if (!title[0]) break;
1781             }
1782             i++;
1783         }
1784     }
1785     retvalue = list[i];
1786
1787  done:
1788     HeapFree( GetProcessHeap(), 0, list );
1789     HeapFree( GetProcessHeap(), 0, buffer );
1790     return retvalue;
1791 }
1792
1793
1794
1795 /***********************************************************************
1796  *              FindWindowA (USER32.@)
1797  */
1798 HWND WINAPI FindWindowA( LPCSTR className, LPCSTR title )
1799 {
1800     HWND ret = FindWindowExA( 0, 0, className, title );
1801     if (!ret) SetLastError (ERROR_CANNOT_FIND_WND_CLASS);
1802     return ret;
1803 }
1804
1805
1806 /***********************************************************************
1807  *              FindWindowExA (USER32.@)
1808  */
1809 HWND WINAPI FindWindowExA( HWND parent, HWND child, LPCSTR className, LPCSTR title )
1810 {
1811     LPWSTR titleW = NULL;
1812     HWND hwnd = 0;
1813
1814     if (title)
1815     {
1816         DWORD len = MultiByteToWideChar( CP_ACP, 0, title, -1, NULL, 0 );
1817         if (!(titleW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return 0;
1818         MultiByteToWideChar( CP_ACP, 0, title, -1, titleW, len );
1819     }
1820
1821     if (!IS_INTRESOURCE(className))
1822     {
1823         WCHAR classW[256];
1824         if (MultiByteToWideChar( CP_ACP, 0, className, -1, classW, sizeof(classW)/sizeof(WCHAR) ))
1825             hwnd = FindWindowExW( parent, child, classW, titleW );
1826     }
1827     else
1828     {
1829         hwnd = FindWindowExW( parent, child, (LPCWSTR)className, titleW );
1830     }
1831
1832     HeapFree( GetProcessHeap(), 0, titleW );
1833     return hwnd;
1834 }
1835
1836
1837 /***********************************************************************
1838  *              FindWindowW (USER32.@)
1839  */
1840 HWND WINAPI FindWindowW( LPCWSTR className, LPCWSTR title )
1841 {
1842     return FindWindowExW( 0, 0, className, title );
1843 }
1844
1845
1846 /**********************************************************************
1847  *              GetDesktopWindow (USER32.@)
1848  */
1849 HWND WINAPI GetDesktopWindow(void)
1850 {
1851     struct user_thread_info *thread_info = get_user_thread_info();
1852
1853     if (thread_info->top_window) return thread_info->top_window;
1854
1855     SERVER_START_REQ( get_desktop_window )
1856     {
1857         req->force = 0;
1858         if (!wine_server_call( req ))
1859         {
1860             thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1861             thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1862         }
1863     }
1864     SERVER_END_REQ;
1865
1866     if (!thread_info->top_window)
1867     {
1868         USEROBJECTFLAGS flags;
1869         if (!GetUserObjectInformationW( GetProcessWindowStation(), UOI_FLAGS, &flags,
1870                                         sizeof(flags), NULL ) || (flags.dwFlags & WSF_VISIBLE))
1871         {
1872             static const WCHAR explorer[] = {'\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
1873             static const WCHAR args[] = {' ','/','d','e','s','k','t','o','p',0};
1874             STARTUPINFOW si;
1875             PROCESS_INFORMATION pi;
1876             WCHAR windir[MAX_PATH];
1877             WCHAR app[MAX_PATH + sizeof(explorer)/sizeof(WCHAR)];
1878             WCHAR cmdline[MAX_PATH + (sizeof(explorer) + sizeof(args))/sizeof(WCHAR)];
1879             void *redir;
1880
1881             memset( &si, 0, sizeof(si) );
1882             si.cb = sizeof(si);
1883             si.dwFlags = STARTF_USESTDHANDLES;
1884             si.hStdInput  = 0;
1885             si.hStdOutput = 0;
1886             si.hStdError  = GetStdHandle( STD_ERROR_HANDLE );
1887
1888             GetSystemDirectoryW( windir, MAX_PATH );
1889             strcpyW( app, windir );
1890             strcatW( app, explorer );
1891             strcpyW( cmdline, app );
1892             strcatW( cmdline, args );
1893
1894             Wow64DisableWow64FsRedirection( &redir );
1895             if (CreateProcessW( app, cmdline, NULL, NULL, FALSE, DETACHED_PROCESS,
1896                                 NULL, windir, &si, &pi ))
1897             {
1898                 TRACE( "started explorer pid %04x tid %04x\n", pi.dwProcessId, pi.dwThreadId );
1899                 WaitForInputIdle( pi.hProcess, 10000 );
1900                 CloseHandle( pi.hThread );
1901                 CloseHandle( pi.hProcess );
1902             }
1903             else WARN( "failed to start explorer, err %d\n", GetLastError() );
1904             Wow64RevertWow64FsRedirection( redir );
1905         }
1906         else TRACE( "not starting explorer since winstation is not visible\n" );
1907
1908         SERVER_START_REQ( get_desktop_window )
1909         {
1910             req->force = 1;
1911             if (!wine_server_call( req ))
1912             {
1913                 thread_info->top_window = wine_server_ptr_handle( reply->top_window );
1914                 thread_info->msg_window = wine_server_ptr_handle( reply->msg_window );
1915             }
1916         }
1917         SERVER_END_REQ;
1918     }
1919
1920     if (!thread_info->top_window || !USER_Driver->pCreateDesktopWindow( thread_info->top_window ))
1921         ERR( "failed to create desktop window\n" );
1922
1923     return thread_info->top_window;
1924 }
1925
1926
1927 /*******************************************************************
1928  *              EnableWindow (USER32.@)
1929  */
1930 BOOL WINAPI EnableWindow( HWND hwnd, BOOL enable )
1931 {
1932     BOOL retvalue;
1933     HWND full_handle;
1934
1935     if (is_broadcast(hwnd))
1936     {
1937         SetLastError( ERROR_INVALID_PARAMETER );
1938         return FALSE;
1939     }
1940
1941     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
1942         return SendMessageW( hwnd, WM_WINE_ENABLEWINDOW, enable, 0 );
1943
1944     hwnd = full_handle;
1945
1946     TRACE("( %p, %d )\n", hwnd, enable);
1947
1948     retvalue = !IsWindowEnabled( hwnd );
1949
1950     if (enable && retvalue)
1951     {
1952         WIN_SetStyle( hwnd, 0, WS_DISABLED );
1953         SendMessageW( hwnd, WM_ENABLE, TRUE, 0 );
1954     }
1955     else if (!enable && !retvalue)
1956     {
1957         HWND capture_wnd;
1958
1959         SendMessageW( hwnd, WM_CANCELMODE, 0, 0);
1960
1961         WIN_SetStyle( hwnd, WS_DISABLED, 0 );
1962
1963         if (hwnd == GetFocus())
1964             SetFocus( 0 );  /* A disabled window can't have the focus */
1965
1966         capture_wnd = GetCapture();
1967         if (hwnd == capture_wnd || IsChild(hwnd, capture_wnd))
1968             ReleaseCapture();  /* A disabled window can't capture the mouse */
1969
1970         SendMessageW( hwnd, WM_ENABLE, FALSE, 0 );
1971     }
1972     return retvalue;
1973 }
1974
1975
1976 /***********************************************************************
1977  *              IsWindowEnabled (USER32.@)
1978  */
1979 BOOL WINAPI IsWindowEnabled(HWND hWnd)
1980 {
1981     return !(GetWindowLongW( hWnd, GWL_STYLE ) & WS_DISABLED);
1982 }
1983
1984
1985 /***********************************************************************
1986  *              IsWindowUnicode (USER32.@)
1987  */
1988 BOOL WINAPI IsWindowUnicode( HWND hwnd )
1989 {
1990     WND * wndPtr;
1991     BOOL retvalue = FALSE;
1992
1993     if (!(wndPtr = WIN_GetPtr(hwnd))) return FALSE;
1994
1995     if (wndPtr == WND_DESKTOP) return TRUE;
1996
1997     if (wndPtr != WND_OTHER_PROCESS)
1998     {
1999         retvalue = (wndPtr->flags & WIN_ISUNICODE) != 0;
2000         WIN_ReleasePtr( wndPtr );
2001     }
2002     else
2003     {
2004         SERVER_START_REQ( get_window_info )
2005         {
2006             req->handle = wine_server_user_handle( hwnd );
2007             if (!wine_server_call_err( req )) retvalue = reply->is_unicode;
2008         }
2009         SERVER_END_REQ;
2010     }
2011     return retvalue;
2012 }
2013
2014
2015 /**********************************************************************
2016  *           WIN_GetWindowLong
2017  *
2018  * Helper function for GetWindowLong().
2019  */
2020 static LONG_PTR WIN_GetWindowLong( HWND hwnd, INT offset, UINT size, BOOL unicode )
2021 {
2022     LONG_PTR retvalue = 0;
2023     WND *wndPtr;
2024
2025     if (offset == GWLP_HWNDPARENT)
2026     {
2027         HWND parent = GetAncestor( hwnd, GA_PARENT );
2028         if (parent == GetDesktopWindow()) parent = GetWindow( hwnd, GW_OWNER );
2029         return (ULONG_PTR)parent;
2030     }
2031
2032     if (!(wndPtr = WIN_GetPtr( hwnd )))
2033     {
2034         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2035         return 0;
2036     }
2037
2038     if (wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP)
2039     {
2040         if (offset == GWLP_WNDPROC)
2041         {
2042             SetLastError( ERROR_ACCESS_DENIED );
2043             return 0;
2044         }
2045         SERVER_START_REQ( set_window_info )
2046         {
2047             req->handle = wine_server_user_handle( hwnd );
2048             req->flags  = 0;  /* don't set anything, just retrieve */
2049             req->extra_offset = (offset >= 0) ? offset : -1;
2050             req->extra_size = (offset >= 0) ? size : 0;
2051             if (!wine_server_call_err( req ))
2052             {
2053                 switch(offset)
2054                 {
2055                 case GWL_STYLE:      retvalue = reply->old_style; break;
2056                 case GWL_EXSTYLE:    retvalue = reply->old_ex_style; break;
2057                 case GWLP_ID:        retvalue = reply->old_id; break;
2058                 case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wine_server_get_ptr( reply->old_instance ); break;
2059                 case GWLP_USERDATA:  retvalue = reply->old_user_data; break;
2060                 default:
2061                     if (offset >= 0) retvalue = get_win_data( &reply->old_extra_value, size );
2062                     else SetLastError( ERROR_INVALID_INDEX );
2063                     break;
2064                 }
2065             }
2066         }
2067         SERVER_END_REQ;
2068         return retvalue;
2069     }
2070
2071     /* now we have a valid wndPtr */
2072
2073     if (offset >= 0)
2074     {
2075         if (offset > (int)(wndPtr->cbWndExtra - size))
2076         {
2077             WARN("Invalid offset %d\n", offset );
2078             WIN_ReleasePtr( wndPtr );
2079             SetLastError( ERROR_INVALID_INDEX );
2080             return 0;
2081         }
2082         retvalue = get_win_data( (char *)wndPtr->wExtra + offset, size );
2083
2084         /* Special case for dialog window procedure */
2085         if ((offset == DWLP_DLGPROC) && (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2086             retvalue = (LONG_PTR)WINPROC_GetProc( (WNDPROC)retvalue, unicode );
2087         WIN_ReleasePtr( wndPtr );
2088         return retvalue;
2089     }
2090
2091     switch(offset)
2092     {
2093     case GWLP_USERDATA:  retvalue = wndPtr->userdata; break;
2094     case GWL_STYLE:      retvalue = wndPtr->dwStyle; break;
2095     case GWL_EXSTYLE:    retvalue = wndPtr->dwExStyle; break;
2096     case GWLP_ID:        retvalue = wndPtr->wIDmenu; break;
2097     case GWLP_HINSTANCE: retvalue = (ULONG_PTR)wndPtr->hInstance; break;
2098     case GWLP_WNDPROC:
2099         /* This looks like a hack only for the edit control (see tests). This makes these controls
2100          * more tolerant to A/W mismatches. The lack of W->A->W conversion for such a mismatch suggests
2101          * that the hack is in GetWindowLongPtr[AW], not in winprocs.
2102          */
2103         if (wndPtr->winproc == BUILTIN_WINPROC(WINPROC_EDIT) && (!unicode != !(wndPtr->flags & WIN_ISUNICODE)))
2104             retvalue = (ULONG_PTR)wndPtr->winproc;
2105         else
2106             retvalue = (ULONG_PTR)WINPROC_GetProc( wndPtr->winproc, unicode );
2107         break;
2108     default:
2109         WARN("Unknown offset %d\n", offset );
2110         SetLastError( ERROR_INVALID_INDEX );
2111         break;
2112     }
2113     WIN_ReleasePtr(wndPtr);
2114     return retvalue;
2115 }
2116
2117
2118 /**********************************************************************
2119  *           WIN_SetWindowLong
2120  *
2121  * Helper function for SetWindowLong().
2122  *
2123  * 0 is the failure code. However, in the case of failure SetLastError
2124  * must be set to distinguish between a 0 return value and a failure.
2125  */
2126 LONG_PTR WIN_SetWindowLong( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOOL unicode )
2127 {
2128     STYLESTRUCT style;
2129     BOOL ok;
2130     LONG_PTR retval = 0;
2131     WND *wndPtr;
2132
2133     TRACE( "%p %d %lx %c\n", hwnd, offset, newval, unicode ? 'W' : 'A' );
2134
2135     if (is_broadcast(hwnd))
2136     {
2137         SetLastError( ERROR_INVALID_PARAMETER );
2138         return FALSE;
2139     }
2140
2141     if (!(wndPtr = WIN_GetPtr( hwnd )))
2142     {
2143         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2144         return 0;
2145     }
2146     if (wndPtr == WND_DESKTOP)
2147     {
2148         /* can't change anything on the desktop window */
2149         SetLastError( ERROR_ACCESS_DENIED );
2150         return 0;
2151     }
2152     if (wndPtr == WND_OTHER_PROCESS)
2153     {
2154         if (offset == GWLP_WNDPROC)
2155         {
2156             SetLastError( ERROR_ACCESS_DENIED );
2157             return 0;
2158         }
2159         if (offset > 32767 || offset < -32767)
2160         {
2161             SetLastError( ERROR_INVALID_INDEX );
2162             return 0;
2163         }
2164         return SendMessageW( hwnd, WM_WINE_SETWINDOWLONG, MAKEWPARAM( offset, size ), newval );
2165     }
2166
2167     /* first some special cases */
2168     switch( offset )
2169     {
2170     case GWL_STYLE:
2171         style.styleOld = wndPtr->dwStyle;
2172         style.styleNew = newval;
2173         WIN_ReleasePtr( wndPtr );
2174         SendMessageW( hwnd, WM_STYLECHANGING, GWL_STYLE, (LPARAM)&style );
2175         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2176         newval = style.styleNew;
2177         /* WS_CLIPSIBLINGS can't be reset on top-level windows */
2178         if (wndPtr->parent == GetDesktopWindow()) newval |= WS_CLIPSIBLINGS;
2179         break;
2180     case GWL_EXSTYLE:
2181         style.styleOld = wndPtr->dwExStyle;
2182         style.styleNew = newval;
2183         WIN_ReleasePtr( wndPtr );
2184         SendMessageW( hwnd, WM_STYLECHANGING, GWL_EXSTYLE, (LPARAM)&style );
2185         if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
2186         /* WS_EX_TOPMOST can only be changed through SetWindowPos */
2187         newval = (style.styleNew & ~WS_EX_TOPMOST) | (wndPtr->dwExStyle & WS_EX_TOPMOST);
2188         /* WS_EX_WINDOWEDGE depends on some other styles */
2189         if ((newval & WS_EX_DLGMODALFRAME) || (wndPtr->dwStyle & WS_THICKFRAME))
2190             newval |= WS_EX_WINDOWEDGE;
2191         else if (wndPtr->dwStyle & (WS_CHILD|WS_POPUP))
2192             newval &= ~WS_EX_WINDOWEDGE;
2193         break;
2194     case GWLP_HWNDPARENT:
2195         if (wndPtr->parent == GetDesktopWindow())
2196         {
2197             WIN_ReleasePtr( wndPtr );
2198             return (ULONG_PTR)WIN_SetOwner( hwnd, (HWND)newval );
2199         }
2200         else
2201         {
2202             WIN_ReleasePtr( wndPtr );
2203             return (ULONG_PTR)SetParent( hwnd, (HWND)newval );
2204         }
2205     case GWLP_WNDPROC:
2206     {
2207         WNDPROC proc;
2208         UINT old_flags = wndPtr->flags;
2209         retval = WIN_GetWindowLong( hwnd, offset, size, unicode );
2210         proc = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2211         if (proc) wndPtr->winproc = proc;
2212         if (WINPROC_IsUnicode( proc, unicode )) wndPtr->flags |= WIN_ISUNICODE;
2213         else wndPtr->flags &= ~WIN_ISUNICODE;
2214         if (!((old_flags ^ wndPtr->flags) & WIN_ISUNICODE))
2215         {
2216             WIN_ReleasePtr( wndPtr );
2217             return retval;
2218         }
2219         /* update is_unicode flag on the server side */
2220         break;
2221     }
2222     case GWLP_ID:
2223     case GWLP_HINSTANCE:
2224     case GWLP_USERDATA:
2225         break;
2226     case DWLP_DLGPROC:
2227         if ((wndPtr->cbWndExtra - sizeof(LONG_PTR) >= DWLP_DLGPROC) &&
2228             (size == sizeof(LONG_PTR)) && wndPtr->dlgInfo)
2229         {
2230             WNDPROC *ptr = (WNDPROC *)((char *)wndPtr->wExtra + DWLP_DLGPROC);
2231             retval = (ULONG_PTR)WINPROC_GetProc( *ptr, unicode );
2232             *ptr = WINPROC_AllocProc( (WNDPROC)newval, unicode );
2233             WIN_ReleasePtr( wndPtr );
2234             return retval;
2235         }
2236         /* fall through */
2237     default:
2238         if (offset < 0 || offset > (int)(wndPtr->cbWndExtra - size))
2239         {
2240             WARN("Invalid offset %d\n", offset );
2241             WIN_ReleasePtr( wndPtr );
2242             SetLastError( ERROR_INVALID_INDEX );
2243             return 0;
2244         }
2245         else if (get_win_data( (char *)wndPtr->wExtra + offset, size ) == newval)
2246         {
2247             /* already set to the same value */
2248             WIN_ReleasePtr( wndPtr );
2249             return newval;
2250         }
2251         break;
2252     }
2253
2254     SERVER_START_REQ( set_window_info )
2255     {
2256         req->handle = wine_server_user_handle( hwnd );
2257         req->extra_offset = -1;
2258         switch(offset)
2259         {
2260         case GWL_STYLE:
2261             req->flags = SET_WIN_STYLE;
2262             req->style = newval;
2263             break;
2264         case GWL_EXSTYLE:
2265             req->flags = SET_WIN_EXSTYLE;
2266             req->ex_style = newval;
2267             break;
2268         case GWLP_ID:
2269             req->flags = SET_WIN_ID;
2270             req->id = newval;
2271             break;
2272         case GWLP_HINSTANCE:
2273             req->flags = SET_WIN_INSTANCE;
2274             req->instance = wine_server_client_ptr( (void *)newval );
2275             break;
2276         case GWLP_WNDPROC:
2277             req->flags = SET_WIN_UNICODE;
2278             req->is_unicode = (wndPtr->flags & WIN_ISUNICODE) != 0;
2279             break;
2280         case GWLP_USERDATA:
2281             req->flags = SET_WIN_USERDATA;
2282             req->user_data = newval;
2283             break;
2284         default:
2285             req->flags = SET_WIN_EXTRA;
2286             req->extra_offset = offset;
2287             req->extra_size = size;
2288             set_win_data( &req->extra_value, newval, size );
2289         }
2290         if ((ok = !wine_server_call_err( req )))
2291         {
2292             switch(offset)
2293             {
2294             case GWL_STYLE:
2295                 wndPtr->dwStyle = newval;
2296                 retval = reply->old_style;
2297                 break;
2298             case GWL_EXSTYLE:
2299                 wndPtr->dwExStyle = newval;
2300                 retval = reply->old_ex_style;
2301                 break;
2302             case GWLP_ID:
2303                 wndPtr->wIDmenu = newval;
2304                 retval = reply->old_id;
2305                 break;
2306             case GWLP_HINSTANCE:
2307                 wndPtr->hInstance = (HINSTANCE)newval;
2308                 retval = (ULONG_PTR)wine_server_get_ptr( reply->old_instance );
2309                 break;
2310             case GWLP_WNDPROC:
2311                 break;
2312             case GWLP_USERDATA:
2313                 wndPtr->userdata = newval;
2314                 retval = reply->old_user_data;
2315                 break;
2316             default:
2317                 retval = get_win_data( (char *)wndPtr->wExtra + offset, size );
2318                 set_win_data( (char *)wndPtr->wExtra + offset, newval, size );
2319                 break;
2320             }
2321         }
2322     }
2323     SERVER_END_REQ;
2324     WIN_ReleasePtr( wndPtr );
2325
2326     if (!ok) return 0;
2327
2328     if (offset == GWL_STYLE || offset == GWL_EXSTYLE)
2329     {
2330         style.styleOld = retval;
2331         style.styleNew = newval;
2332         USER_Driver->pSetWindowStyle( hwnd, offset, &style );
2333         SendMessageW( hwnd, WM_STYLECHANGED, offset, (LPARAM)&style );
2334     }
2335
2336     return retval;
2337 }
2338
2339
2340 /**********************************************************************
2341  *              GetWindowWord (USER32.@)
2342  */
2343 WORD WINAPI GetWindowWord( HWND hwnd, INT offset )
2344 {
2345     switch(offset)
2346     {
2347     case GWLP_ID:
2348     case GWLP_HINSTANCE:
2349     case GWLP_HWNDPARENT:
2350         break;
2351     default:
2352         if (offset < 0)
2353         {
2354             WARN("Invalid offset %d\n", offset );
2355             SetLastError( ERROR_INVALID_INDEX );
2356             return 0;
2357         }
2358         break;
2359     }
2360     return WIN_GetWindowLong( hwnd, offset, sizeof(WORD), FALSE );
2361 }
2362
2363
2364 /**********************************************************************
2365  *              GetWindowLongA (USER32.@)
2366  */
2367 LONG WINAPI GetWindowLongA( HWND hwnd, INT offset )
2368 {
2369     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), FALSE );
2370 }
2371
2372
2373 /**********************************************************************
2374  *              GetWindowLongW (USER32.@)
2375  */
2376 LONG WINAPI GetWindowLongW( HWND hwnd, INT offset )
2377 {
2378     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG), TRUE );
2379 }
2380
2381
2382 /**********************************************************************
2383  *              SetWindowWord (USER32.@)
2384  */
2385 WORD WINAPI SetWindowWord( HWND hwnd, INT offset, WORD newval )
2386 {
2387     switch(offset)
2388     {
2389     case GWLP_ID:
2390     case GWLP_HINSTANCE:
2391     case GWLP_HWNDPARENT:
2392         break;
2393     default:
2394         if (offset < 0)
2395         {
2396             WARN("Invalid offset %d\n", offset );
2397             SetLastError( ERROR_INVALID_INDEX );
2398             return 0;
2399         }
2400         break;
2401     }
2402     return WIN_SetWindowLong( hwnd, offset, sizeof(WORD), newval, FALSE );
2403 }
2404
2405
2406 /**********************************************************************
2407  *              SetWindowLongA (USER32.@)
2408  *
2409  * See SetWindowLongW.
2410  */
2411 LONG WINAPI SetWindowLongA( HWND hwnd, INT offset, LONG newval )
2412 {
2413     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, FALSE );
2414 }
2415
2416
2417 /**********************************************************************
2418  *              SetWindowLongW (USER32.@) Set window attribute
2419  *
2420  * SetWindowLong() alters one of a window's attributes or sets a 32-bit (long)
2421  * value in a window's extra memory.
2422  *
2423  * The _hwnd_ parameter specifies the window.  is the handle to a
2424  * window that has extra memory. The _newval_ parameter contains the
2425  * new attribute or extra memory value.  If positive, the _offset_
2426  * parameter is the byte-addressed location in the window's extra
2427  * memory to set.  If negative, _offset_ specifies the window
2428  * attribute to set, and should be one of the following values:
2429  *
2430  * GWL_EXSTYLE      The window's extended window style
2431  *
2432  * GWL_STYLE        The window's window style.
2433  *
2434  * GWLP_WNDPROC     Pointer to the window's window procedure.
2435  *
2436  * GWLP_HINSTANCE   The window's pplication instance handle.
2437  *
2438  * GWLP_ID          The window's identifier.
2439  *
2440  * GWLP_USERDATA    The window's user-specified data.
2441  *
2442  * If the window is a dialog box, the _offset_ parameter can be one of
2443  * the following values:
2444  *
2445  * DWLP_DLGPROC     The address of the window's dialog box procedure.
2446  *
2447  * DWLP_MSGRESULT   The return value of a message
2448  *                  that the dialog box procedure processed.
2449  *
2450  * DWLP_USER        Application specific information.
2451  *
2452  * RETURNS
2453  *
2454  * If successful, returns the previous value located at _offset_. Otherwise,
2455  * returns 0.
2456  *
2457  * NOTES
2458  *
2459  * Extra memory for a window class is specified by a nonzero cbWndExtra
2460  * parameter of the WNDCLASS structure passed to RegisterClass() at the
2461  * time of class creation.
2462  *
2463  * Using GWL_WNDPROC to set a new window procedure effectively creates
2464  * a window subclass. Use CallWindowProc() in the new windows procedure
2465  * to pass messages to the superclass's window procedure.
2466  *
2467  * The user data is reserved for use by the application which created
2468  * the window.
2469  *
2470  * Do not use GWL_STYLE to change the window's WS_DISABLED style;
2471  * instead, call the EnableWindow() function to change the window's
2472  * disabled state.
2473  *
2474  * Do not use GWL_HWNDPARENT to reset the window's parent, use
2475  * SetParent() instead.
2476  *
2477  * Win95:
2478  * When offset is GWL_STYLE and the calling app's ver is 4.0,
2479  * it sends WM_STYLECHANGING before changing the settings
2480  * and WM_STYLECHANGED afterwards.
2481  * App ver 4.0 can't use SetWindowLong to change WS_EX_TOPMOST.
2482  */
2483 LONG WINAPI SetWindowLongW(
2484     HWND hwnd,  /* [in] window to alter */
2485     INT offset, /* [in] offset, in bytes, of location to alter */
2486     LONG newval /* [in] new value of location */
2487 ) {
2488     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG), newval, TRUE );
2489 }
2490
2491
2492 /*******************************************************************
2493  *              GetWindowTextA (USER32.@)
2494  */
2495 INT WINAPI GetWindowTextA( HWND hwnd, LPSTR lpString, INT nMaxCount )
2496 {
2497     WCHAR *buffer;
2498
2499     if (!lpString) return 0;
2500
2501     if (WIN_IsCurrentProcess( hwnd ))
2502         return (INT)SendMessageA( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2503
2504     /* when window belongs to other process, don't send a message */
2505     if (nMaxCount <= 0) return 0;
2506     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, nMaxCount * sizeof(WCHAR) ))) return 0;
2507     get_server_window_text( hwnd, buffer, nMaxCount );
2508     if (!WideCharToMultiByte( CP_ACP, 0, buffer, -1, lpString, nMaxCount, NULL, NULL ))
2509         lpString[nMaxCount-1] = 0;
2510     HeapFree( GetProcessHeap(), 0, buffer );
2511     return strlen(lpString);
2512 }
2513
2514
2515 /*******************************************************************
2516  *              InternalGetWindowText (USER32.@)
2517  */
2518 INT WINAPI InternalGetWindowText(HWND hwnd,LPWSTR lpString,INT nMaxCount )
2519 {
2520     WND *win;
2521
2522     if (nMaxCount <= 0) return 0;
2523     if (!(win = WIN_GetPtr( hwnd ))) return 0;
2524     if (win == WND_DESKTOP) lpString[0] = 0;
2525     else if (win != WND_OTHER_PROCESS)
2526     {
2527         if (win->text) lstrcpynW( lpString, win->text, nMaxCount );
2528         else lpString[0] = 0;
2529         WIN_ReleasePtr( win );
2530     }
2531     else
2532     {
2533         get_server_window_text( hwnd, lpString, nMaxCount );
2534     }
2535     return strlenW(lpString);
2536 }
2537
2538
2539 /*******************************************************************
2540  *              GetWindowTextW (USER32.@)
2541  */
2542 INT WINAPI GetWindowTextW( HWND hwnd, LPWSTR lpString, INT nMaxCount )
2543 {
2544     if (!lpString) return 0;
2545
2546     if (WIN_IsCurrentProcess( hwnd ))
2547         return (INT)SendMessageW( hwnd, WM_GETTEXT, nMaxCount, (LPARAM)lpString );
2548
2549     /* when window belongs to other process, don't send a message */
2550     if (nMaxCount <= 0) return 0;
2551     get_server_window_text( hwnd, lpString, nMaxCount );
2552     return strlenW(lpString);
2553 }
2554
2555
2556 /*******************************************************************
2557  *              SetWindowTextA (USER32.@)
2558  *              SetWindowText  (USER32.@)
2559  */
2560 BOOL WINAPI SetWindowTextA( HWND hwnd, LPCSTR lpString )
2561 {
2562     if (is_broadcast(hwnd))
2563     {
2564         SetLastError( ERROR_INVALID_PARAMETER );
2565         return FALSE;
2566     }
2567     if (!WIN_IsCurrentProcess( hwnd ))
2568         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2569                debugstr_a(lpString), hwnd );
2570     return (BOOL)SendMessageA( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2571 }
2572
2573
2574 /*******************************************************************
2575  *              SetWindowTextW (USER32.@)
2576  */
2577 BOOL WINAPI SetWindowTextW( HWND hwnd, LPCWSTR lpString )
2578 {
2579     if (is_broadcast(hwnd))
2580     {
2581         SetLastError( ERROR_INVALID_PARAMETER );
2582         return FALSE;
2583     }
2584     if (!WIN_IsCurrentProcess( hwnd ))
2585         WARN( "setting text %s of other process window %p should not use SendMessage\n",
2586                debugstr_w(lpString), hwnd );
2587     return (BOOL)SendMessageW( hwnd, WM_SETTEXT, 0, (LPARAM)lpString );
2588 }
2589
2590
2591 /*******************************************************************
2592  *              GetWindowTextLengthA (USER32.@)
2593  */
2594 INT WINAPI GetWindowTextLengthA( HWND hwnd )
2595 {
2596     return SendMessageA( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2597 }
2598
2599 /*******************************************************************
2600  *              GetWindowTextLengthW (USER32.@)
2601  */
2602 INT WINAPI GetWindowTextLengthW( HWND hwnd )
2603 {
2604     return SendMessageW( hwnd, WM_GETTEXTLENGTH, 0, 0 );
2605 }
2606
2607
2608 /*******************************************************************
2609  *              IsWindow (USER32.@)
2610  */
2611 BOOL WINAPI IsWindow( HWND hwnd )
2612 {
2613     WND *ptr;
2614     BOOL ret;
2615
2616     if (!(ptr = WIN_GetPtr( hwnd ))) return FALSE;
2617     if (ptr == WND_DESKTOP) return TRUE;
2618
2619     if (ptr != WND_OTHER_PROCESS)
2620     {
2621         WIN_ReleasePtr( ptr );
2622         return TRUE;
2623     }
2624
2625     /* check other processes */
2626     SERVER_START_REQ( get_window_info )
2627     {
2628         req->handle = wine_server_user_handle( hwnd );
2629         ret = !wine_server_call_err( req );
2630     }
2631     SERVER_END_REQ;
2632     return ret;
2633 }
2634
2635
2636 /***********************************************************************
2637  *              GetWindowThreadProcessId (USER32.@)
2638  */
2639 DWORD WINAPI GetWindowThreadProcessId( HWND hwnd, LPDWORD process )
2640 {
2641     WND *ptr;
2642     DWORD tid = 0;
2643
2644     if (!(ptr = WIN_GetPtr( hwnd )))
2645     {
2646         SetLastError( ERROR_INVALID_WINDOW_HANDLE);
2647         return 0;
2648     }
2649
2650     if (ptr != WND_OTHER_PROCESS && ptr != WND_DESKTOP)
2651     {
2652         /* got a valid window */
2653         tid = ptr->tid;
2654         if (process) *process = GetCurrentProcessId();
2655         WIN_ReleasePtr( ptr );
2656         return tid;
2657     }
2658
2659     /* check other processes */
2660     SERVER_START_REQ( get_window_info )
2661     {
2662         req->handle = wine_server_user_handle( hwnd );
2663         if (!wine_server_call_err( req ))
2664         {
2665             tid = (DWORD)reply->tid;
2666             if (process) *process = (DWORD)reply->pid;
2667         }
2668     }
2669     SERVER_END_REQ;
2670     return tid;
2671 }
2672
2673
2674 /*****************************************************************
2675  *              GetParent (USER32.@)
2676  */
2677 HWND WINAPI GetParent( HWND hwnd )
2678 {
2679     WND *wndPtr;
2680     HWND retvalue = 0;
2681
2682     if (!(wndPtr = WIN_GetPtr( hwnd )))
2683     {
2684         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2685         return 0;
2686     }
2687     if (wndPtr == WND_DESKTOP) return 0;
2688     if (wndPtr == WND_OTHER_PROCESS)
2689     {
2690         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2691         if (style & (WS_POPUP | WS_CHILD))
2692         {
2693             SERVER_START_REQ( get_window_tree )
2694             {
2695                 req->handle = wine_server_user_handle( hwnd );
2696                 if (!wine_server_call_err( req ))
2697                 {
2698                     if (style & WS_POPUP) retvalue = wine_server_ptr_handle( reply->owner );
2699                     else if (style & WS_CHILD) retvalue = wine_server_ptr_handle( reply->parent );
2700                 }
2701             }
2702             SERVER_END_REQ;
2703         }
2704     }
2705     else
2706     {
2707         if (wndPtr->dwStyle & WS_POPUP) retvalue = wndPtr->owner;
2708         else if (wndPtr->dwStyle & WS_CHILD) retvalue = wndPtr->parent;
2709         WIN_ReleasePtr( wndPtr );
2710     }
2711     return retvalue;
2712 }
2713
2714
2715 /*****************************************************************
2716  *              GetAncestor (USER32.@)
2717  */
2718 HWND WINAPI GetAncestor( HWND hwnd, UINT type )
2719 {
2720     WND *win;
2721     HWND *list, ret = 0;
2722
2723     switch(type)
2724     {
2725     case GA_PARENT:
2726         if (!(win = WIN_GetPtr( hwnd )))
2727         {
2728             SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2729             return 0;
2730         }
2731         if (win == WND_DESKTOP) return 0;
2732         if (win != WND_OTHER_PROCESS)
2733         {
2734             ret = win->parent;
2735             WIN_ReleasePtr( win );
2736         }
2737         else /* need to query the server */
2738         {
2739             SERVER_START_REQ( get_window_tree )
2740             {
2741                 req->handle = wine_server_user_handle( hwnd );
2742                 if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->parent );
2743             }
2744             SERVER_END_REQ;
2745         }
2746         break;
2747
2748     case GA_ROOT:
2749         if (!(list = list_window_parents( hwnd ))) return 0;
2750
2751         if (!list[0] || !list[1]) ret = WIN_GetFullHandle( hwnd );  /* top-level window */
2752         else
2753         {
2754             int count = 2;
2755             while (list[count]) count++;
2756             ret = list[count - 2];  /* get the one before the desktop */
2757         }
2758         HeapFree( GetProcessHeap(), 0, list );
2759         break;
2760
2761     case GA_ROOTOWNER:
2762         if (is_desktop_window( hwnd )) return 0;
2763         ret = WIN_GetFullHandle( hwnd );
2764         for (;;)
2765         {
2766             HWND parent = GetParent( ret );
2767             if (!parent) break;
2768             ret = parent;
2769         }
2770         break;
2771     }
2772     return ret;
2773 }
2774
2775
2776 /*****************************************************************
2777  *              SetParent (USER32.@)
2778  */
2779 HWND WINAPI SetParent( HWND hwnd, HWND parent )
2780 {
2781     HWND full_handle;
2782     HWND old_parent = 0;
2783     BOOL was_visible;
2784     WND *wndPtr;
2785     BOOL ret;
2786
2787     if (is_broadcast(hwnd) || is_broadcast(parent))
2788     {
2789         SetLastError(ERROR_INVALID_PARAMETER);
2790         return 0;
2791     }
2792
2793     if (!parent) parent = GetDesktopWindow();
2794     else if (parent == HWND_MESSAGE) parent = get_hwnd_message_parent();
2795     else parent = WIN_GetFullHandle( parent );
2796
2797     if (!IsWindow( parent ))
2798     {
2799         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2800         return 0;
2801     }
2802
2803     /* Some applications try to set a child as a parent */
2804     if (IsChild(hwnd, parent))
2805     {
2806         SetLastError( ERROR_INVALID_PARAMETER );
2807         return 0;
2808     }
2809
2810     if (!(full_handle = WIN_IsCurrentThread( hwnd )))
2811         return (HWND)SendMessageW( hwnd, WM_WINE_SETPARENT, (WPARAM)parent, 0 );
2812
2813     if (full_handle == parent)
2814     {
2815         SetLastError( ERROR_INVALID_PARAMETER );
2816         return 0;
2817     }
2818
2819     /* Windows hides the window first, then shows it again
2820      * including the WM_SHOWWINDOW messages and all */
2821     was_visible = ShowWindow( hwnd, SW_HIDE );
2822
2823     wndPtr = WIN_GetPtr( hwnd );
2824     if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return 0;
2825
2826     SERVER_START_REQ( set_parent )
2827     {
2828         req->handle = wine_server_user_handle( hwnd );
2829         req->parent = wine_server_user_handle( parent );
2830         if ((ret = !wine_server_call( req )))
2831         {
2832             old_parent = wine_server_ptr_handle( reply->old_parent );
2833             wndPtr->parent = parent = wine_server_ptr_handle( reply->full_parent );
2834         }
2835
2836     }
2837     SERVER_END_REQ;
2838     WIN_ReleasePtr( wndPtr );
2839     if (!ret) return 0;
2840
2841     USER_Driver->pSetParent( full_handle, parent, old_parent );
2842
2843     /* SetParent additionally needs to make hwnd the topmost window
2844        in the x-order and send the expected WM_WINDOWPOSCHANGING and
2845        WM_WINDOWPOSCHANGED notification messages.
2846     */
2847     SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0,
2848                   SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | (was_visible ? SWP_SHOWWINDOW : 0) );
2849     /* FIXME: a WM_MOVE is also generated (in the DefWindowProc handler
2850      * for WM_WINDOWPOSCHANGED) in Windows, should probably remove SWP_NOMOVE */
2851
2852     return old_parent;
2853 }
2854
2855
2856 /*******************************************************************
2857  *              IsChild (USER32.@)
2858  */
2859 BOOL WINAPI IsChild( HWND parent, HWND child )
2860 {
2861     HWND *list = list_window_parents( child );
2862     int i;
2863     BOOL ret;
2864
2865     if (!list) return FALSE;
2866     parent = WIN_GetFullHandle( parent );
2867     for (i = 0; list[i]; i++) if (list[i] == parent) break;
2868     ret = list[i] && list[i+1];
2869     HeapFree( GetProcessHeap(), 0, list );
2870     return ret;
2871 }
2872
2873
2874 /***********************************************************************
2875  *              IsWindowVisible (USER32.@)
2876  */
2877 BOOL WINAPI IsWindowVisible( HWND hwnd )
2878 {
2879     HWND *list;
2880     BOOL retval = TRUE;
2881     int i;
2882
2883     if (!(GetWindowLongW( hwnd, GWL_STYLE ) & WS_VISIBLE)) return FALSE;
2884     if (!(list = list_window_parents( hwnd ))) return TRUE;
2885     if (list[0])
2886     {
2887         for (i = 0; list[i+1]; i++)
2888             if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) break;
2889         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2890     }
2891     HeapFree( GetProcessHeap(), 0, list );
2892     return retval;
2893 }
2894
2895
2896 /***********************************************************************
2897  *           WIN_IsWindowDrawable
2898  *
2899  * hwnd is drawable when it is visible, all parents are not
2900  * minimized, and it is itself not minimized unless we are
2901  * trying to draw its default class icon.
2902  */
2903 BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL icon )
2904 {
2905     HWND *list;
2906     BOOL retval = TRUE;
2907     int i;
2908     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
2909
2910     if (!(style & WS_VISIBLE)) return FALSE;
2911     if ((style & WS_MINIMIZE) && icon && GetClassLongPtrW( hwnd, GCLP_HICON ))  return FALSE;
2912
2913     if (!(list = list_window_parents( hwnd ))) return TRUE;
2914     if (list[0])
2915     {
2916         for (i = 0; list[i+1]; i++)
2917             if ((GetWindowLongW( list[i], GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != WS_VISIBLE)
2918                 break;
2919         retval = !list[i+1] && (list[i] == GetDesktopWindow());  /* top message window isn't visible */
2920     }
2921     HeapFree( GetProcessHeap(), 0, list );
2922     return retval;
2923 }
2924
2925
2926 /*******************************************************************
2927  *              GetTopWindow (USER32.@)
2928  */
2929 HWND WINAPI GetTopWindow( HWND hwnd )
2930 {
2931     if (!hwnd) hwnd = GetDesktopWindow();
2932     return GetWindow( hwnd, GW_CHILD );
2933 }
2934
2935
2936 /*******************************************************************
2937  *              GetWindow (USER32.@)
2938  */
2939 HWND WINAPI GetWindow( HWND hwnd, UINT rel )
2940 {
2941     HWND retval = 0;
2942
2943     if (rel == GW_OWNER)  /* this one may be available locally */
2944     {
2945         WND *wndPtr = WIN_GetPtr( hwnd );
2946         if (!wndPtr)
2947         {
2948             SetLastError( ERROR_INVALID_HANDLE );
2949             return 0;
2950         }
2951         if (wndPtr == WND_DESKTOP) return 0;
2952         if (wndPtr != WND_OTHER_PROCESS)
2953         {
2954             retval = wndPtr->owner;
2955             WIN_ReleasePtr( wndPtr );
2956             return retval;
2957         }
2958         /* else fall through to server call */
2959     }
2960
2961     SERVER_START_REQ( get_window_tree )
2962     {
2963         req->handle = wine_server_user_handle( hwnd );
2964         if (!wine_server_call_err( req ))
2965         {
2966             switch(rel)
2967             {
2968             case GW_HWNDFIRST:
2969                 retval = wine_server_ptr_handle( reply->first_sibling );
2970                 break;
2971             case GW_HWNDLAST:
2972                 retval = wine_server_ptr_handle( reply->last_sibling );
2973                 break;
2974             case GW_HWNDNEXT:
2975                 retval = wine_server_ptr_handle( reply->next_sibling );
2976                 break;
2977             case GW_HWNDPREV:
2978                 retval = wine_server_ptr_handle( reply->prev_sibling );
2979                 break;
2980             case GW_OWNER:
2981                 retval = wine_server_ptr_handle( reply->owner );
2982                 break;
2983             case GW_CHILD:
2984                 retval = wine_server_ptr_handle( reply->first_child );
2985                 break;
2986             }
2987         }
2988     }
2989     SERVER_END_REQ;
2990     return retval;
2991 }
2992
2993
2994 /*******************************************************************
2995  *              ShowOwnedPopups (USER32.@)
2996  */
2997 BOOL WINAPI ShowOwnedPopups( HWND owner, BOOL fShow )
2998 {
2999     int count = 0;
3000     WND *pWnd;
3001     HWND *win_array = WIN_ListChildren( GetDesktopWindow() );
3002
3003     if (!win_array) return TRUE;
3004
3005     while (win_array[count]) count++;
3006     while (--count >= 0)
3007     {
3008         if (GetWindow( win_array[count], GW_OWNER ) != owner) continue;
3009         if (!(pWnd = WIN_GetPtr( win_array[count] ))) continue;
3010         if (pWnd == WND_OTHER_PROCESS) continue;
3011         if (fShow)
3012         {
3013             if (pWnd->flags & WIN_NEEDS_SHOW_OWNEDPOPUP)
3014             {
3015                 WIN_ReleasePtr( pWnd );
3016                 /* In Windows, ShowOwnedPopups(TRUE) generates
3017                  * WM_SHOWWINDOW messages with SW_PARENTOPENING,
3018                  * regardless of the state of the owner
3019                  */
3020                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_SHOWNORMAL, SW_PARENTOPENING);
3021                 continue;
3022             }
3023         }
3024         else
3025         {
3026             if (pWnd->dwStyle & WS_VISIBLE)
3027             {
3028                 WIN_ReleasePtr( pWnd );
3029                 /* In Windows, ShowOwnedPopups(FALSE) generates
3030                  * WM_SHOWWINDOW messages with SW_PARENTCLOSING,
3031                  * regardless of the state of the owner
3032                  */
3033                 SendMessageW(win_array[count], WM_SHOWWINDOW, SW_HIDE, SW_PARENTCLOSING);
3034                 continue;
3035             }
3036         }
3037         WIN_ReleasePtr( pWnd );
3038     }
3039     HeapFree( GetProcessHeap(), 0, win_array );
3040     return TRUE;
3041 }
3042
3043
3044 /*******************************************************************
3045  *              GetLastActivePopup (USER32.@)
3046  */
3047 HWND WINAPI GetLastActivePopup( HWND hwnd )
3048 {
3049     HWND retval = hwnd;
3050
3051     SERVER_START_REQ( get_window_info )
3052     {
3053         req->handle = wine_server_user_handle( hwnd );
3054         if (!wine_server_call_err( req )) retval = wine_server_ptr_handle( reply->last_active );
3055     }
3056     SERVER_END_REQ;
3057     return retval;
3058 }
3059
3060
3061 /*******************************************************************
3062  *           WIN_ListChildren
3063  *
3064  * Build an array of the children of a given window. The array must be
3065  * freed with HeapFree. Returns NULL when no windows are found.
3066  */
3067 HWND *WIN_ListChildren( HWND hwnd )
3068 {
3069     if (!hwnd)
3070     {
3071         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3072         return NULL;
3073     }
3074     return list_window_children( 0, hwnd, NULL, 0 );
3075 }
3076
3077
3078 /*******************************************************************
3079  *              EnumWindows (USER32.@)
3080  */
3081 BOOL WINAPI EnumWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
3082 {
3083     HWND *list;
3084     BOOL ret = TRUE;
3085     int i;
3086
3087     USER_CheckNotLock();
3088
3089     /* We have to build a list of all windows first, to avoid */
3090     /* unpleasant side-effects, for instance if the callback */
3091     /* function changes the Z-order of the windows.          */
3092
3093     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return TRUE;
3094
3095     /* Now call the callback function for every window */
3096
3097     for (i = 0; list[i]; i++)
3098     {
3099         /* Make sure that the window still exists */
3100         if (!IsWindow( list[i] )) continue;
3101         if (!(ret = lpEnumFunc( list[i], lParam ))) break;
3102     }
3103     HeapFree( GetProcessHeap(), 0, list );
3104     return ret;
3105 }
3106
3107
3108 /**********************************************************************
3109  *              EnumThreadWindows (USER32.@)
3110  */
3111 BOOL WINAPI EnumThreadWindows( DWORD id, WNDENUMPROC func, LPARAM lParam )
3112 {
3113     HWND *list;
3114     int i;
3115     BOOL ret = TRUE;
3116
3117     USER_CheckNotLock();
3118
3119     if (!(list = list_window_children( 0, GetDesktopWindow(), NULL, id ))) return TRUE;
3120
3121     /* Now call the callback function for every window */
3122
3123     for (i = 0; list[i]; i++)
3124         if (!(ret = func( list[i], lParam ))) break;
3125     HeapFree( GetProcessHeap(), 0, list );
3126     return ret;
3127 }
3128
3129
3130 /***********************************************************************
3131  *              EnumDesktopWindows   (USER32.@)
3132  */
3133 BOOL WINAPI EnumDesktopWindows( HDESK desktop, WNDENUMPROC func, LPARAM lparam )
3134 {
3135     HWND *list;
3136     int i;
3137
3138     USER_CheckNotLock();
3139
3140     if (!(list = list_window_children( desktop, 0, NULL, 0 ))) return TRUE;
3141
3142     for (i = 0; list[i]; i++)
3143         if (!func( list[i], lparam )) break;
3144     HeapFree( GetProcessHeap(), 0, list );
3145     return TRUE;
3146 }
3147
3148
3149 /**********************************************************************
3150  *           WIN_EnumChildWindows
3151  *
3152  * Helper function for EnumChildWindows().
3153  */
3154 static BOOL WIN_EnumChildWindows( HWND *list, WNDENUMPROC func, LPARAM lParam )
3155 {
3156     HWND *childList;
3157     BOOL ret = FALSE;
3158
3159     for ( ; *list; list++)
3160     {
3161         /* Make sure that the window still exists */
3162         if (!IsWindow( *list )) continue;
3163         /* Build children list first */
3164         childList = WIN_ListChildren( *list );
3165
3166         ret = func( *list, lParam );
3167
3168         if (childList)
3169         {
3170             if (ret) ret = WIN_EnumChildWindows( childList, func, lParam );
3171             HeapFree( GetProcessHeap(), 0, childList );
3172         }
3173         if (!ret) return FALSE;
3174     }
3175     return TRUE;
3176 }
3177
3178
3179 /**********************************************************************
3180  *              EnumChildWindows (USER32.@)
3181  */
3182 BOOL WINAPI EnumChildWindows( HWND parent, WNDENUMPROC func, LPARAM lParam )
3183 {
3184     HWND *list;
3185     BOOL ret;
3186
3187     USER_CheckNotLock();
3188
3189     if (!(list = WIN_ListChildren( parent ))) return FALSE;
3190     ret = WIN_EnumChildWindows( list, func, lParam );
3191     HeapFree( GetProcessHeap(), 0, list );
3192     return ret;
3193 }
3194
3195
3196 /*******************************************************************
3197  *              AnyPopup (USER32.@)
3198  */
3199 BOOL WINAPI AnyPopup(void)
3200 {
3201     int i;
3202     BOOL retvalue;
3203     HWND *list = WIN_ListChildren( GetDesktopWindow() );
3204
3205     if (!list) return FALSE;
3206     for (i = 0; list[i]; i++)
3207     {
3208         if (IsWindowVisible( list[i] ) && GetWindow( list[i], GW_OWNER )) break;
3209     }
3210     retvalue = (list[i] != 0);
3211     HeapFree( GetProcessHeap(), 0, list );
3212     return retvalue;
3213 }
3214
3215
3216 /*******************************************************************
3217  *              FlashWindow (USER32.@)
3218  */
3219 BOOL WINAPI FlashWindow( HWND hWnd, BOOL bInvert )
3220 {
3221     WND *wndPtr;
3222
3223     TRACE("%p\n", hWnd);
3224
3225     if (IsIconic( hWnd ))
3226     {
3227         RedrawWindow( hWnd, 0, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_FRAME );
3228
3229         wndPtr = WIN_GetPtr(hWnd);
3230         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3231         if (bInvert && !(wndPtr->flags & WIN_NCACTIVATED))
3232         {
3233             wndPtr->flags |= WIN_NCACTIVATED;
3234         }
3235         else
3236         {
3237             wndPtr->flags &= ~WIN_NCACTIVATED;
3238         }
3239         WIN_ReleasePtr( wndPtr );
3240         return TRUE;
3241     }
3242     else
3243     {
3244         WPARAM wparam;
3245
3246         wndPtr = WIN_GetPtr(hWnd);
3247         if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
3248         hWnd = wndPtr->obj.handle;  /* make it a full handle */
3249
3250         if (bInvert) wparam = !(wndPtr->flags & WIN_NCACTIVATED);
3251         else wparam = (hWnd == GetForegroundWindow());
3252
3253         WIN_ReleasePtr( wndPtr );
3254         SendMessageW( hWnd, WM_NCACTIVATE, wparam, 0 );
3255         return wparam;
3256     }
3257 }
3258
3259 /*******************************************************************
3260  *              FlashWindowEx (USER32.@)
3261  */
3262 BOOL WINAPI FlashWindowEx( PFLASHWINFO pfwi )
3263 {
3264     FIXME("%p\n", pfwi);
3265     return TRUE;
3266 }
3267
3268 /*******************************************************************
3269  *              GetWindowContextHelpId (USER32.@)
3270  */
3271 DWORD WINAPI GetWindowContextHelpId( HWND hwnd )
3272 {
3273     DWORD retval;
3274     WND *wnd = WIN_GetPtr( hwnd );
3275     if (!wnd || wnd == WND_DESKTOP) return 0;
3276     if (wnd == WND_OTHER_PROCESS)
3277     {
3278         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3279         return 0;
3280     }
3281     retval = wnd->helpContext;
3282     WIN_ReleasePtr( wnd );
3283     return retval;
3284 }
3285
3286
3287 /*******************************************************************
3288  *              SetWindowContextHelpId (USER32.@)
3289  */
3290 BOOL WINAPI SetWindowContextHelpId( HWND hwnd, DWORD id )
3291 {
3292     WND *wnd = WIN_GetPtr( hwnd );
3293     if (!wnd || wnd == WND_DESKTOP) return FALSE;
3294     if (wnd == WND_OTHER_PROCESS)
3295     {
3296         if (IsWindow( hwnd )) FIXME( "not supported on other process window %p\n", hwnd );
3297         return 0;
3298     }
3299     wnd->helpContext = id;
3300     WIN_ReleasePtr( wnd );
3301     return TRUE;
3302 }
3303
3304
3305 /*******************************************************************
3306  *              DragDetect (USER32.@)
3307  */
3308 BOOL WINAPI DragDetect( HWND hWnd, POINT pt )
3309 {
3310     MSG msg;
3311     RECT rect;
3312     WORD wDragWidth = GetSystemMetrics(SM_CXDRAG);
3313     WORD wDragHeight= GetSystemMetrics(SM_CYDRAG);
3314
3315     rect.left = pt.x - wDragWidth;
3316     rect.right = pt.x + wDragWidth;
3317
3318     rect.top = pt.y - wDragHeight;
3319     rect.bottom = pt.y + wDragHeight;
3320
3321     SetCapture(hWnd);
3322
3323     while(1)
3324     {
3325         while (PeekMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ))
3326         {
3327             if( msg.message == WM_LBUTTONUP )
3328             {
3329                 ReleaseCapture();
3330                 return 0;
3331             }
3332             if( msg.message == WM_MOUSEMOVE )
3333             {
3334                 POINT tmp;
3335                 tmp.x = (short)LOWORD(msg.lParam);
3336                 tmp.y = (short)HIWORD(msg.lParam);
3337                 if( !PtInRect( &rect, tmp ))
3338                 {
3339                     ReleaseCapture();
3340                     return 1;
3341                 }
3342             }
3343         }
3344         WaitMessage();
3345     }
3346     return 0;
3347 }
3348
3349 /******************************************************************************
3350  *              GetWindowModuleFileNameA (USER32.@)
3351  */
3352 UINT WINAPI GetWindowModuleFileNameA( HWND hwnd, LPSTR module, UINT size )
3353 {
3354     WND *win;
3355     HINSTANCE hinst;
3356
3357     TRACE( "%p, %p, %u\n", hwnd, module, size );
3358
3359     win = WIN_GetPtr( hwnd );
3360     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3361     {
3362         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3363         return 0;
3364     }
3365     hinst = win->hInstance;
3366     WIN_ReleasePtr( win );
3367
3368     return GetModuleFileNameA( hinst, module, size );
3369 }
3370
3371 /******************************************************************************
3372  *              GetWindowModuleFileNameW (USER32.@)
3373  */
3374 UINT WINAPI GetWindowModuleFileNameW( HWND hwnd, LPWSTR module, UINT size )
3375 {
3376     WND *win;
3377     HINSTANCE hinst;
3378
3379     TRACE( "%p, %p, %u\n", hwnd, module, size );
3380
3381     win = WIN_GetPtr( hwnd );
3382     if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP)
3383     {
3384         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
3385         return 0;
3386     }
3387     hinst = win->hInstance;
3388     WIN_ReleasePtr( win );
3389
3390     return GetModuleFileNameW( hinst, module, size );
3391 }
3392
3393 /******************************************************************************
3394  *              GetWindowInfo (USER32.@)
3395  *
3396  * Note: tests show that Windows doesn't check cbSize of the structure.
3397  */
3398 BOOL WINAPI GetWindowInfo( HWND hwnd, PWINDOWINFO pwi)
3399 {
3400     if (!pwi) return FALSE;
3401     if (!WIN_GetRectangles( hwnd, COORDS_SCREEN, &pwi->rcWindow, &pwi->rcClient )) return FALSE;
3402
3403     pwi->dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
3404     pwi->dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
3405     pwi->dwWindowStatus = ((GetActiveWindow() == hwnd) ? WS_ACTIVECAPTION : 0);
3406
3407     pwi->cxWindowBorders = pwi->rcClient.left - pwi->rcWindow.left;
3408     pwi->cyWindowBorders = pwi->rcWindow.bottom - pwi->rcClient.bottom;
3409
3410     pwi->atomWindowType = GetClassLongW( hwnd, GCW_ATOM );
3411     pwi->wCreatorVersion = 0x0400;
3412
3413     return TRUE;
3414 }
3415
3416 /******************************************************************************
3417  *              SwitchDesktop (USER32.@)
3418  *
3419  * NOTES: Sets the current input or interactive desktop.
3420  */
3421 BOOL WINAPI SwitchDesktop( HDESK hDesktop)
3422 {
3423     FIXME("(hwnd %p) stub!\n", hDesktop);
3424     return TRUE;
3425 }
3426
3427 /*****************************************************************************
3428  *              SetLayeredWindowAttributes (USER32.@)
3429  */
3430 BOOL WINAPI SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWORD flags )
3431 {
3432     BOOL ret;
3433
3434     TRACE("(%p,%08x,%d,%x): stub!\n", hwnd, key, alpha, flags);
3435
3436     SERVER_START_REQ( set_window_layered_info )
3437     {
3438         req->handle = wine_server_user_handle( hwnd );
3439         req->color_key = key;
3440         req->alpha = alpha;
3441         req->flags = flags;
3442         ret = !wine_server_call_err( req );
3443     }
3444     SERVER_END_REQ;
3445
3446     if (ret) USER_Driver->pSetLayeredWindowAttributes( hwnd, key, alpha, flags );
3447
3448     return ret;
3449 }
3450
3451
3452 /*****************************************************************************
3453  *              GetLayeredWindowAttributes (USER32.@)
3454  */
3455 BOOL WINAPI GetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *alpha, DWORD *flags )
3456 {
3457     BOOL ret;
3458
3459     SERVER_START_REQ( get_window_layered_info )
3460     {
3461         req->handle = wine_server_user_handle( hwnd );
3462         if ((ret = !wine_server_call_err( req )))
3463         {
3464             if (key) *key = reply->color_key;
3465             if (alpha) *alpha = reply->alpha;
3466             if (flags) *flags = reply->flags;
3467         }
3468     }
3469     SERVER_END_REQ;
3470
3471     return ret;
3472 }
3473
3474
3475 /*****************************************************************************
3476  *              UpdateLayeredWindowIndirect  (USER32.@)
3477  */
3478 BOOL WINAPI UpdateLayeredWindowIndirect( HWND hwnd, const UPDATELAYEREDWINDOWINFO *info )
3479 {
3480     BYTE alpha = 0xff;
3481
3482     if (!(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_LAYERED) ||
3483         GetLayeredWindowAttributes( hwnd, NULL, NULL, NULL ))
3484     {
3485         SetLastError( ERROR_INVALID_PARAMETER );
3486         return FALSE;
3487     }
3488
3489     if (!(info->dwFlags & ULW_EX_NORESIZE) && (info->pptDst || info->psize))
3490     {
3491         int x = 0, y = 0, cx = 0, cy = 0;
3492         DWORD flags = SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSENDCHANGING;
3493
3494         if (info->pptDst)
3495         {
3496             x = info->pptDst->x;
3497             y = info->pptDst->y;
3498             flags &= ~SWP_NOMOVE;
3499         }
3500         if (info->psize)
3501         {
3502             cx = info->psize->cx;
3503             cy = info->psize->cy;
3504             flags &= ~SWP_NOSIZE;
3505         }
3506         TRACE( "moving window %p pos %d,%d %dx%d\n", hwnd, x, y, cx, cy );
3507         SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
3508     }
3509
3510     if (info->hdcSrc)
3511     {
3512         HDC hdc = GetWindowDC( hwnd );
3513
3514         if (hdc)
3515         {
3516             int x = 0, y = 0;
3517             RECT rect;
3518
3519             GetWindowRect( hwnd, &rect );
3520             OffsetRect( &rect, -rect.left, -rect.top);
3521             if (info->pptSrc)
3522             {
3523                 x = info->pptSrc->x;
3524                 y = info->pptSrc->y;
3525             }
3526
3527             if (!info->prcDirty || (info->prcDirty && IntersectRect(&rect, &rect, info->prcDirty)))
3528             {
3529                 TRACE( "copying window %p pos %d,%d\n", hwnd, x, y );
3530                 BitBlt( hdc, rect.left, rect.top, rect.right, rect.bottom,
3531                         info->hdcSrc, rect.left + x, rect.top + y, SRCCOPY );
3532             }
3533             ReleaseDC( hwnd, hdc );
3534         }
3535     }
3536
3537     if (info->pblend && !(info->dwFlags & ULW_OPAQUE)) alpha = info->pblend->SourceConstantAlpha;
3538     TRACE( "setting window %p alpha %u\n", hwnd, alpha );
3539     USER_Driver->pSetLayeredWindowAttributes( hwnd, info->crKey, alpha,
3540                                               info->dwFlags & (LWA_ALPHA | LWA_COLORKEY) );
3541     return TRUE;
3542 }
3543
3544
3545 /*****************************************************************************
3546  *              UpdateLayeredWindow (USER32.@)
3547  */
3548 BOOL WINAPI UpdateLayeredWindow( HWND hwnd, HDC hdcDst, POINT *pptDst, SIZE *psize,
3549                                  HDC hdcSrc, POINT *pptSrc, COLORREF crKey, BLENDFUNCTION *pblend,
3550                                  DWORD dwFlags)
3551 {
3552     UPDATELAYEREDWINDOWINFO info;
3553
3554     info.cbSize   = sizeof(info);
3555     info.hdcDst   = hdcDst;
3556     info.pptDst   = pptDst;
3557     info.psize    = psize;
3558     info.hdcSrc   = hdcSrc;
3559     info.pptSrc   = pptSrc;
3560     info.crKey    = crKey;
3561     info.pblend   = pblend;
3562     info.dwFlags  = dwFlags;
3563     info.prcDirty = NULL;
3564     return UpdateLayeredWindowIndirect( hwnd, &info );
3565 }
3566
3567
3568 /******************************************************************************
3569  *                    GetProcessDefaultLayout [USER32.@]
3570  *
3571  * Gets the default layout for parentless windows.
3572  */
3573 BOOL WINAPI GetProcessDefaultLayout( DWORD *layout )
3574 {
3575     if (!layout)
3576     {
3577         SetLastError( ERROR_NOACCESS );
3578         return FALSE;
3579     }
3580     if (process_layout == ~0u)
3581     {
3582         static const WCHAR translationW[] = { '\\','V','a','r','F','i','l','e','I','n','f','o',
3583                                               '\\','T','r','a','n','s','l','a','t','i','o','n', 0 };
3584         static const WCHAR filedescW[] = { '\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o',
3585                                            '\\','%','0','4','x','%','0','4','x',
3586                                            '\\','F','i','l','e','D','e','s','c','r','i','p','t','i','o','n',0 };
3587         WCHAR *str, buffer[MAX_PATH];
3588         DWORD i, len, version_layout = 0;
3589         DWORD user_lang = GetUserDefaultLangID();
3590         DWORD *languages;
3591         void *data = NULL;
3592
3593         GetModuleFileNameW( 0, buffer, MAX_PATH );
3594         if (!(len = GetFileVersionInfoSizeW( buffer, NULL ))) goto done;
3595         if (!(data = HeapAlloc( GetProcessHeap(), 0, len ))) goto done;
3596         if (!GetFileVersionInfoW( buffer, 0, len, data )) goto done;
3597         if (!VerQueryValueW( data, translationW, (void **)&languages, &len ) || !len) goto done;
3598
3599         len /= sizeof(DWORD);
3600         for (i = 0; i < len; i++) if (LOWORD(languages[i]) == user_lang) break;
3601         if (i == len)  /* try neutral language */
3602             for (i = 0; i < len; i++)
3603                 if (LOWORD(languages[i]) == MAKELANGID( PRIMARYLANGID(user_lang), SUBLANG_NEUTRAL )) break;
3604         if (i == len) i = 0;  /* default to the first one */
3605
3606         sprintfW( buffer, filedescW, LOWORD(languages[i]), HIWORD(languages[i]) );
3607         if (!VerQueryValueW( data, buffer, (void **)&str, &len )) goto done;
3608         TRACE( "found description %s\n", debugstr_w( str ));
3609         if (str[0] == 0x200e && str[1] == 0x200e) version_layout = LAYOUT_RTL;
3610
3611     done:
3612         HeapFree( GetProcessHeap(), 0, data );
3613         process_layout = version_layout;
3614     }
3615     *layout = process_layout;
3616     return TRUE;
3617 }
3618
3619
3620 /******************************************************************************
3621  *                    SetProcessDefaultLayout [USER32.@]
3622  *
3623  * Sets the default layout for parentless windows.
3624  */
3625 BOOL WINAPI SetProcessDefaultLayout( DWORD layout )
3626 {
3627     process_layout = layout;
3628     return TRUE;
3629 }
3630
3631
3632 /* 64bit versions */
3633
3634 #ifdef GetWindowLongPtrW
3635 #undef GetWindowLongPtrW
3636 #endif
3637
3638 #ifdef GetWindowLongPtrA
3639 #undef GetWindowLongPtrA
3640 #endif
3641
3642 #ifdef SetWindowLongPtrW
3643 #undef SetWindowLongPtrW
3644 #endif
3645
3646 #ifdef SetWindowLongPtrA
3647 #undef SetWindowLongPtrA
3648 #endif
3649
3650 /*****************************************************************************
3651  *              GetWindowLongPtrW (USER32.@)
3652  */
3653 LONG_PTR WINAPI GetWindowLongPtrW( HWND hwnd, INT offset )
3654 {
3655     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), TRUE );
3656 }
3657
3658 /*****************************************************************************
3659  *              GetWindowLongPtrA (USER32.@)
3660  */
3661 LONG_PTR WINAPI GetWindowLongPtrA( HWND hwnd, INT offset )
3662 {
3663     return WIN_GetWindowLong( hwnd, offset, sizeof(LONG_PTR), FALSE );
3664 }
3665
3666 /*****************************************************************************
3667  *              SetWindowLongPtrW (USER32.@)
3668  */
3669 LONG_PTR WINAPI SetWindowLongPtrW( HWND hwnd, INT offset, LONG_PTR newval )
3670 {
3671     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, TRUE );
3672 }
3673
3674 /*****************************************************************************
3675  *              SetWindowLongPtrA (USER32.@)
3676  */
3677 LONG_PTR WINAPI SetWindowLongPtrA( HWND hwnd, INT offset, LONG_PTR newval )
3678 {
3679     return WIN_SetWindowLong( hwnd, offset, sizeof(LONG_PTR), newval, FALSE );
3680 }